1 /* Copyright 1988, 1996 by the Massachusetts Institute of Technology.
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions
5  * are met:
6  *
7  * * Redistributions of source code must retain the above copyright
8  *   notice, this list of conditions and the following disclaimer.
9  *
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in
12  *   the documentation and/or other materials provided with the
13  *   distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26  * OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /* This file is a test driver for the Hesiod library. */
30 
31 static const char rcsid[] = "$Id: hestest.c,v 1.3 1999-10-23 19:29:16 danw Exp $";
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include <netdb.h>
38 #include <errno.h>
39 #include <pwd.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <stdarg.h>
43 #include "hesiod.h"
44 
45 static char *word_end(char *s);
46 static char *find_word(char *s);
47 static char *get_word(char *p, char *buf);
48 static char *get_field(char *p, int delim, char *buf);
49 static int compare_vector(char **vector, char *spec);
50 static int compare_pwnam(struct passwd *pw, char *spec);
51 static int compare_serv(struct servent *serv, char *spec);
52 static int compare_office(struct hesiod_postoffice *office, char *spec);
53 static int compare_compat_office(struct hes_postoffice *office, char *spec);
54 static void free_ptrs(char **ptrs);
55 static void failure(const char *fmt, ...);
56 
57 int saw_failure = 0;
58 
main(int argc,char ** argv)59 int main(int argc, char **argv)
60 {
61   FILE *fp;
62   char buf[1024], *p, *q, name[128], type[128], proto[128], **list;
63   int line, errval;
64   struct passwd *pw;
65   struct servent *serv;
66   struct hesiod_postoffice *po;
67   struct hes_postoffice *compatpo;
68   void *context;
69 
70   if (argc != 2)
71     {
72       fprintf(stderr, "Usage: %s filename\n", argv[0]);
73       return 1;
74     }
75 
76   fp = fopen(argv[1], "r");
77   if (!fp)
78     {
79       fprintf(stderr, "Couldn't open %s for reading.\n", argv[1]);
80       return 1;
81     }
82 
83   if (hesiod_init(&context) < 0)
84     {
85       fprintf(stderr, "Can't initialize hesiod library.\n");
86       return 1;
87     }
88 
89   line = 0;
90   while (fgets(buf, sizeof(buf), fp))
91     {
92       line++;
93 
94       /* Strip off trailing spaces (inefficiently). */
95       while (isspace((unsigned char)buf[strlen(buf) - 1]))
96 	buf[strlen(buf) - 1] = 0;
97 
98       /* Get the first word, discard comment lines and invalid lines. */
99       q = word_end(p = find_word(buf));
100       if (*p == '#' || !*p)
101 	continue;
102 
103       if (*q && q - p == 7 && strncmp(p, "resolve", 7) == 0)
104 	{
105 	  /* Test for hesiod_resolve and hes_resolve. */
106 	  q = get_word(find_word(q), name);
107 	  q = get_word(find_word(q), type);
108 	  p = find_word(q);
109 	  list = hesiod_resolve(context, name, type);
110 	  errval = errno;
111 	  if (!list && !(*p == 'E' && p[1] == 0))
112 	    {
113 	      failure("Line %d failed (hesiod_resolve error %d).\n", line,
114 		      errval);
115 	      continue;
116 	    }
117 	  if (list && compare_vector(list, p) < 0)
118 	    {
119 	      failure("Line %d failed in hesiod_resolve().\n", line);
120 	      hesiod_free_list(context, list);
121 	      continue;
122 	    }
123 	  if (list)
124 	    hesiod_free_list(context, list);
125 	  list = hes_resolve(name, type);
126 	  if (!list)
127 	    {
128 	      if (*p == 'E' && p[1] == 0)
129 		printf("Line %d passed (%d, %d).\n", line, errval,
130 		       hes_error());
131 	      else
132 		failure("Line %d failed (hes_resolve error %d).\n", line,
133 			hes_error());
134 	      continue;
135 	    }
136 	  if (compare_vector(list, p) < 0)
137 	    failure("Line %d failed in hes_resolve().\n", line);
138 	  else
139 	    printf("Line %d passed.\n", line);
140 	  free_ptrs(list);
141 	}
142       else if (*q && q - p == 8 && strncmp(p, "getpwnam", 8) == 0)
143 	{
144 	  /* Test for hesiod_getpwnam and hes_getpwnam. */
145 	  q = get_word(find_word(q), name);
146 	  p = find_word(q);
147 	  pw = hesiod_getpwnam(context, name);
148 	  errval = errno;
149 	  if (!pw && !(*p == 'E' && p[1] == 0))
150 	    {
151 	      failure("Line %d failed (hesiod_getpwnam error %d).\n", line,
152 		      errval);
153 	      continue;
154 	    }
155 	  if (pw && compare_pwnam(pw, p) < 0)
156 	    {
157 	      failure("Line %d failed in hesiod_getpwnam().\n", line);
158 	      continue;
159 	    }
160 	  if (pw)
161 	    hesiod_free_passwd(context, pw);
162 	  pw = hes_getpwnam(name);
163 	  if (!pw)
164 	    {
165 	      if (*p == 'E' && p[1] == 0)
166 		printf("Line %d passed (%d, %d).\n", line, errval,
167 		       hes_error());
168 	      else
169 		failure("Line %d failed (hes_getpwnam error %d).\n", line,
170 			hes_error());
171 	      continue;
172 	    }
173 	  if (compare_pwnam(pw, p) < 0)
174 	    failure("Line %d failed in hes_getpwnam().\n", line);
175 	  else
176 	    printf("Line %d passed.\n", line);
177 	}
178       else if (*q && q - p == 8 && strncmp(p, "getpwuid", 8) == 0)
179 	{
180 	  /* Test for hesiod_getpwuid and hes_getpwuid. */
181 	  q = get_word(find_word(q), name);
182 	  p = find_word(q);
183 	  pw = hesiod_getpwuid(context, atoi(name));
184 	  errval = errno;
185 	  if (!pw && !(*p == 'E' && p[1] == 0))
186 	    {
187 	      failure("Line %d failed (hesiod_getpwuid error %d).\n", line,
188 		      errval);
189 	      continue;
190 	    }
191 	  if (pw && compare_pwnam(pw, p) < 0)
192 	    {
193 	      failure("Line %d failed in hesiod_getpwuid().\n", line);
194 	      continue;
195 	    }
196 	  if (pw)
197 	    hesiod_free_passwd(context, pw);
198 	  pw = hes_getpwuid(atoi(name));
199 	  if (!pw)
200 	    {
201 	      if (*p == 'E' && p[1] == 0)
202 		printf("Line %d passed (%d, %d).\n", line, errval,
203 		       hes_error());
204 	      else
205 		failure("Line %d failed (hes_getpwuid error %d).\n", line,
206 			hes_error());
207 	      continue;
208 	    }
209 	  if (compare_pwnam(pw, p) < 0)
210 	    failure("Line %d failed in hes_getpwuid().\n", line);
211 	  else
212 	    printf("Line %d passed.\n", line);
213 	}
214       else if (*q && q - p == 13 && strncmp(p, "getservbyname", 13) == 0)
215 	{
216 	  /* Test for hesiod_getservbyname and hes_getservbyname. */
217 	  q = get_word(find_word(q), name);
218 	  q = get_word(find_word(q), proto);
219 	  p = find_word(q);
220 	  serv = hesiod_getservbyname(context, name, proto);
221 	  errval = errno;
222 	  if (!serv && !(*p == 'E' && p[1] == 0))
223 	    {
224 	      failure("Line %d failed (hesiod_getservbyname error %d).\n",
225 		      line, errno);
226 	      continue;
227 	    }
228 	  if (serv && compare_serv(serv, p) < 0)
229 	    {
230 	      failure("Line %d failed in hesiod_getservbyname.\n", line);
231 	      continue;
232 	    }
233 	  if (serv)
234 	    hesiod_free_servent(context, serv);
235 	  serv = hes_getservbyname(name, proto);
236 	  if (!serv)
237 	    {
238 	      if (*p == 'E' && p[1] == 0)
239 		printf("Line %d passed (%d, %d).\n", line, errval,
240 		       hes_error());
241 	      else
242 		failure("Line %d failed (hes_getservbyname error %d).\n", line,
243 			hes_error());
244 	      continue;
245 	    }
246 	  if (compare_serv(serv, p) < 0)
247 	    failure("Line %d failed in hes_getservbyname().\n", line);
248 	  else
249 	    printf("Line %d passed.\n", line);
250 	}
251       else if (*q && q - p == 11 && strncmp(p, "getmailhost", 11) == 0)
252 	{
253 	  /* Test for hesiod_getmailhost and hes_getmailhost. */
254 	  q = get_word(find_word(q), name);
255 	  p = find_word(q);
256 	  po = hesiod_getmailhost(context, name);
257 	  errval = errno;
258 	  if (!po && !(*p == 'E' && p[1] == 0))
259 	    {
260 	      failure("Line %d failed (hesiod_getmailhost error %d).\n",
261 		      line, errval);
262 	      continue;
263 	    }
264 	  if (po && compare_office(po, p) < 0)
265 	    {
266 	      failure("Line %d failed in hesiod_getmailhost.\n", line);
267 	      continue;
268 	    }
269 	  if (po)
270 	    hesiod_free_postoffice(context, po);
271 	  compatpo = hes_getmailhost(name);
272 	  if (!compatpo)
273 	    {
274 	      if (*p == 'E' && p[1] == 0)
275 		printf("Line %d passed (%d, %d).\n", line, errval,
276 		       hes_error());
277 	      else
278 		failure("Line %d failed (hes_getmailhost error %d).\n", line,
279 			hes_error());
280 	      continue;
281 	    }
282 	  if (compare_compat_office(compatpo, p) < 0)
283 	    failure("Line %d failed in hes_getmailhost().\n", line);
284 	  else
285 	    printf("Line %d passed.\n", line);
286 
287 	}
288       else
289 	{
290 	  fprintf(stderr, "Line %d invalid: %s\n", line, buf);
291 	  return 2;
292 	}
293     }
294 
295   return saw_failure;
296 }
297 
word_end(char * s)298 static char *word_end(char *s)
299 {
300   while (*s && !isspace((unsigned char)*s))
301     s++;
302   return s;
303 }
304 
find_word(char * s)305 static char *find_word(char *s)
306 {
307   while (isspace((unsigned char)*s))
308     s++;
309   return s;
310 }
311 
get_word(char * p,char * buf)312 static char *get_word(char *p, char *buf)
313 {
314   char *q = word_end(p);
315 
316   strncpy(buf, p, q - p);
317   buf[q - p] = 0;
318   return q;
319 }
320 
get_field(char * p,int delim,char * buf)321 static char *get_field(char *p, int delim, char *buf)
322 {
323   char *q = strchr(p, delim);
324 
325   if (q) {
326     strncpy(buf, p, q - p);
327     buf[q - p] = 0;
328     return q + 1;
329   } else {
330     strcpy(buf, p);
331     return NULL;
332   }
333 }
334 
compare_vector(char ** vector,char * spec)335 static int compare_vector(char **vector, char *spec)
336 {
337   char field[100];
338 
339   for (; *vector; vector++) {
340     spec = get_field(spec, '\\', field);
341     if ((!spec && vector[1]) || strcmp(*vector, field) != 0)
342       return -1;
343   }
344   return (spec) ? -1 : 0;
345 }
346 
compare_pwnam(struct passwd * pw,char * spec)347 static int compare_pwnam(struct passwd *pw, char *spec)
348 {
349   char field[100];
350 
351   spec = get_field(spec, ':', field);
352   if (!spec || strcmp(pw->pw_name, field) != 0)
353     return -1;
354   spec = get_field(spec, ':', field);
355   if (!spec || strcmp(pw->pw_passwd, field) != 0)
356     return -1;
357   spec = get_field(spec, ':', field);
358   if (pw->pw_uid != atoi(field))
359     return -1;
360   spec = get_field(spec, ':', field);
361   if (pw->pw_gid != atoi(field))
362     return -1;
363   spec = get_field(spec, ':', field);
364   if (!spec || strcmp(pw->pw_gecos, field) != 0)
365     return -1;
366   spec = get_field(spec, ':', field);
367   if (!spec || strcmp(pw->pw_dir, field) != 0)
368     return -1;
369   spec = get_field(spec, ':', field);
370   if (spec || strcmp(pw->pw_shell, field) != 0)
371     return -1;
372   return 0;
373 }
374 
compare_serv(struct servent * serv,char * spec)375 static int compare_serv(struct servent *serv, char *spec)
376 {
377   char field[100], **aliases;
378 
379   spec = get_field(spec, ':', field);
380   if (!spec || strcmp(serv->s_name, field) != 0)
381     return -1;
382   spec = get_field(spec, ':', field);
383   if (!spec || strcmp(serv->s_proto, field) != 0)
384     return -1;
385   spec = get_field(spec, ':', field);
386   if (serv->s_port != htons(atoi(field)))
387     return -1;
388   for (aliases = serv->s_aliases; *aliases; aliases++)
389     {
390       if (!spec)
391 	return -1;
392       spec = get_field(spec, '\\', field);
393       if (strcmp(*aliases, field) != 0)
394 	return -1;
395     }
396   return (spec) ? -1 : 0;
397 }
398 
compare_office(struct hesiod_postoffice * office,char * spec)399 static int compare_office(struct hesiod_postoffice *office, char *spec)
400 {
401   char field[100];
402 
403   spec = get_field(spec, ':', field);
404   if (!spec || strcmp(office->hesiod_po_type, field) != 0)
405     return -1;
406   spec = get_field(spec, ':', field);
407   if (!spec || strcmp(office->hesiod_po_host, field) != 0)
408     return -1;
409   spec = get_field(spec, ':', field);
410   if (spec || strcmp(office->hesiod_po_name, field) != 0)
411     return -1;
412   return 0;
413 }
414 
compare_compat_office(struct hes_postoffice * office,char * spec)415 static int compare_compat_office(struct hes_postoffice *office, char *spec)
416 {
417   char field[100];
418 
419   spec = get_field(spec, ':', field);
420   if (!spec || strcmp(office->po_type, field) != 0)
421     return -1;
422   spec = get_field(spec, ':', field);
423   if (!spec || strcmp(office->po_host, field) != 0)
424     return -1;
425   spec = get_field(spec, ':', field);
426   if (spec || strcmp(office->po_name, field) != 0)
427     return -1;
428   return 0;
429 }
430 
free_ptrs(char ** ptrs)431 static void free_ptrs(char **ptrs)
432 {
433   for (; *ptrs; ptrs++)
434     free(*ptrs);
435 }
436 
failure(const char * fmt,...)437 static void failure(const char *fmt, ...)
438 {
439   va_list ap;
440 
441   saw_failure = 1;
442   va_start(ap, fmt);
443   vprintf(fmt, ap);
444   va_end(ap);
445 }
446