1 /*
2  * Copyright(c) 1989, 1993, 1995
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /*
35  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
36  * Portions Copyright (c) 1996 by Internet Software Consortium.
37  *
38  * Permission to use, copy, modify, and distribute this software for any
39  * purpose with or without fee is hereby granted, provided that the above
40  * copyright notice and this permission notice appear in all copies.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
43  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
44  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
45  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
47  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
48  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49  */
50 
51 #if defined(LIBC_SCCS) && !defined(lint)
52 static const char rcsid[] = "$Id: irpmarshall.c,v 1.7 2006/03/09 23:57:56 marka Exp $";
53 #endif /* LIBC_SCCS and not lint */
54 
55 #if 0
56 
57 Check values are in approrpriate endian order.
58 
59 Double check memory allocations on unmarhsalling
60 
61 #endif
62 
63 
64 /* Extern */
65 
66 #include "port_before.h"
67 
68 #include <sys/types.h>
69 #include <sys/socket.h>
70 
71 #include <netinet/in.h>
72 #include <arpa/inet.h>
73 #include <arpa/nameser.h>
74 
75 #include <stdio.h>
76 #include <ctype.h>
77 #include <pwd.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <syslog.h>
81 #include <unistd.h>
82 #include <assert.h>
83 #include <errno.h>
84 
85 #include <irs.h>
86 #include <isc/memcluster.h>
87 #include <isc/irpmarshall.h>
88 
89 #include "port_after.h"
90 
91 
92 #ifndef HAVE_STRNDUP
93 static char    *strndup(const char *str, size_t len);
94 #endif
95 
96 static char   **splitarray(const char *buffer, const char *buffend, char delim);
97 static int	joinarray(char * const * argv, char *buffer, char delim);
98 static char    *getfield(char **res, size_t reslen, char **buffer, char delim);
99 static size_t	joinlength(char * const *argv);
100 static void	free_array(char **argv, size_t entries);
101 
102 #define ADDR_T_STR(x) (x == AF_INET ? "AF_INET" :\
103 		       (x == AF_INET6 ? "AF_INET6" : "UNKNOWN"))
104 
105 #define MAXPADDRSIZE (sizeof "255.255.255.255" + 1)
106 
107 static char COMMA = ',';
108 
109 static const char *COMMASTR = ",";
110 static const char *COLONSTR = ":";
111 
112 
113 
114 /* See big comment at bottom of irpmarshall.h for description. */
115 
116 
117 #ifdef WANT_IRS_PW
118 /* +++++++++++++++++++++++++ struct passwd +++++++++++++++++++++++++ */
119 
120 /*%
121  * int irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len)
122  *
123  * notes: \li
124  *
125  *	See irpmarshall.h
126  *
127  * return: \li
128  *
129  *	0 on sucess, -1 on failure.
130  *
131  */
132 
133 int
irp_marshall_pw(const struct passwd * pw,char ** buffer,size_t * len)134 irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len) {
135 	size_t need = 1 ;		/*%< for null byte */
136 	char pwUid[24];
137 	char pwGid[24];
138 	char pwChange[24];
139 	char pwExpire[24];
140 	const char *pwClass;
141 	const char *fieldsep = COLONSTR;
142 
143 	if (pw == NULL || len == NULL) {
144 		errno = EINVAL;
145 		return (-1);
146 	}
147 
148 	sprintf(pwUid, "%ld", (long)pw->pw_uid);
149 	sprintf(pwGid, "%ld", (long)pw->pw_gid);
150 
151 #ifdef HAVE_PW_CHANGE
152 	sprintf(pwChange, "%ld", (long)pw->pw_change);
153 #else
154 	pwChange[0] = '0';
155 	pwChange[1] = '\0';
156 #endif
157 
158 #ifdef HAVE_PW_EXPIRE
159 	sprintf(pwExpire, "%ld", (long)pw->pw_expire);
160 #else
161 	pwExpire[0] = '0';
162 	pwExpire[1] = '\0';
163 #endif
164 
165 #ifdef HAVE_PW_CLASS
166 	pwClass = pw->pw_class;
167 #else
168 	pwClass = "";
169 #endif
170 
171 	need += strlen(pw->pw_name)	+ 1; /*%< one for fieldsep */
172 	need += strlen(pw->pw_passwd)	+ 1;
173 	need += strlen(pwUid)		+ 1;
174 	need += strlen(pwGid)		+ 1;
175 	need += strlen(pwClass)		+ 1;
176 	need += strlen(pwChange)	+ 1;
177 	need += strlen(pwExpire)	+ 1;
178 	need += strlen(pw->pw_gecos)	+ 1;
179 	need += strlen(pw->pw_dir)	+ 1;
180 	need += strlen(pw->pw_shell)	+ 1;
181 
182 	if (buffer == NULL) {
183 		*len = need;
184 		return (0);
185 	}
186 
187 	if (*buffer != NULL && need > *len) {
188 		errno = EINVAL;
189 		return (-1);
190 	}
191 
192 	if (*buffer == NULL) {
193 		need += 2;		/*%< for CRLF */
194 		*buffer = memget(need);
195 		if (*buffer == NULL) {
196 			errno = ENOMEM;
197 			return (-1);
198 		}
199 
200 		*len = need;
201 	}
202 
203 	strcpy(*buffer, pw->pw_name);		strcat(*buffer, fieldsep);
204 	strcat(*buffer, pw->pw_passwd);		strcat(*buffer, fieldsep);
205 	strcat(*buffer, pwUid);			strcat(*buffer, fieldsep);
206 	strcat(*buffer, pwGid);			strcat(*buffer, fieldsep);
207 	strcat(*buffer, pwClass);		strcat(*buffer, fieldsep);
208 	strcat(*buffer, pwChange);		strcat(*buffer, fieldsep);
209 	strcat(*buffer, pwExpire);		strcat(*buffer, fieldsep);
210 	strcat(*buffer, pw->pw_gecos);		strcat(*buffer, fieldsep);
211 	strcat(*buffer, pw->pw_dir);		strcat(*buffer, fieldsep);
212 	strcat(*buffer, pw->pw_shell);		strcat(*buffer, fieldsep);
213 
214 	return (0);
215 }
216 
217 /*%
218  * int irp_unmarshall_pw(struct passwd *pw, char *buffer)
219  *
220  * notes: \li
221  *
222  *	See irpmarshall.h
223  *
224  * return: \li
225  *
226  *	0 on success, -1 on failure
227  *
228  */
229 
230 int
irp_unmarshall_pw(struct passwd * pw,char * buffer)231 irp_unmarshall_pw(struct passwd *pw, char *buffer) {
232 	char *name, *pass, *class, *gecos, *dir, *shell;
233 	uid_t pwuid;
234 	gid_t pwgid;
235 	time_t pwchange;
236 	time_t pwexpire;
237 	char *p;
238 	long t;
239 	char tmpbuf[24];
240 	char *tb = &tmpbuf[0];
241 	char fieldsep = ':';
242 	int myerrno = EINVAL;
243 
244 	name = pass = class = gecos = dir = shell = NULL;
245 	p = buffer;
246 
247 	/* pw_name field */
248 	name = NULL;
249 	if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
250 		goto error;
251 	}
252 
253 	/* pw_passwd field */
254 	pass = NULL;
255 	if (getfield(&pass, 0, &p, fieldsep) == NULL) { /*%< field can be empty */
256 		goto error;
257 	}
258 
259 
260 	/* pw_uid field */
261 	tb = tmpbuf;
262 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
263 	    strlen(tb) == 0) {
264 		goto error;
265 	}
266 	t = strtol(tmpbuf, &tb, 10);
267 	if (*tb) {
268 		goto error;	/*%< junk in value */
269 	}
270 	pwuid = (uid_t)t;
271 	if ((long) pwuid != t) {	/*%< value must have been too big. */
272 		goto error;
273 	}
274 
275 
276 
277 	/* pw_gid field */
278 	tb = tmpbuf;
279 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
280 	    strlen(tb) == 0) {
281 		goto error;
282 	}
283 	t = strtol(tmpbuf, &tb, 10);
284 	if (*tb) {
285 		goto error;	/*%< junk in value */
286 	}
287 	pwgid = (gid_t)t;
288 	if ((long)pwgid != t) {	/*%< value must have been too big. */
289 		goto error;
290 	}
291 
292 
293 
294 	/* pw_class field */
295 	class = NULL;
296 	if (getfield(&class, 0, &p, fieldsep) == NULL) {
297 		goto error;
298 	}
299 
300 
301 
302 	/* pw_change field */
303 	tb = tmpbuf;
304 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
305 	    strlen(tb) == 0) {
306 		goto error;
307 	}
308 	t = strtol(tmpbuf, &tb, 10);
309 	if (*tb) {
310 		goto error;	/*%< junk in value */
311 	}
312 	pwchange = (time_t)t;
313 	if ((long)pwchange != t) {	/*%< value must have been too big. */
314 		goto error;
315 	}
316 
317 
318 
319 	/* pw_expire field */
320 	tb = tmpbuf;
321 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
322 	    strlen(tb) == 0) {
323 		goto error;
324 	}
325 	t = strtol(tmpbuf, &tb, 10);
326 	if (*tb) {
327 		goto error;	/*%< junk in value */
328 	}
329 	pwexpire = (time_t)t;
330 	if ((long) pwexpire != t) {	/*%< value must have been too big. */
331 		goto error;
332 	}
333 
334 
335 
336 	/* pw_gecos field */
337 	gecos = NULL;
338 	if (getfield(&gecos, 0, &p, fieldsep) == NULL) {
339 		goto error;
340 	}
341 
342 
343 
344 	/* pw_dir field */
345 	dir = NULL;
346 	if (getfield(&dir, 0, &p, fieldsep) == NULL) {
347 		goto error;
348 	}
349 
350 
351 
352 	/* pw_shell field */
353 	shell = NULL;
354 	if (getfield(&shell, 0, &p, fieldsep) == NULL) {
355 		goto error;
356 	}
357 
358 
359 
360 	pw->pw_name = name;
361 	pw->pw_passwd = pass;
362 	pw->pw_uid = pwuid;
363 	pw->pw_gid = pwgid;
364 	pw->pw_gecos = gecos;
365 	pw->pw_dir = dir;
366 	pw->pw_shell = shell;
367 
368 #ifdef HAVE_PW_CHANGE
369 	pw->pw_change = pwchange;
370 #endif
371 #ifdef HAVE_PW_CLASS
372 	pw->pw_class = class;
373 #endif
374 #ifdef HAVE_PW_EXPIRE
375 	pw->pw_expire = pwexpire;
376 #endif
377 
378 	return (0);
379 
380  error:
381 	errno = myerrno;
382 
383 	if (name != NULL) free(name);
384 	if (pass != NULL) free(pass);
385 	if (gecos != NULL) free(gecos);
386 	if (dir != NULL) free(dir);
387 	if (shell != NULL) free(shell);
388 
389 	return (-1);
390 }
391 
392 /* ------------------------- struct passwd ------------------------- */
393 #endif /* WANT_IRS_PW */
394 /* +++++++++++++++++++++++++ struct group +++++++++++++++++++++++++ */
395 
396 /*%
397  * int irp_marshall_gr(const struct group *gr, char **buffer, size_t *len)
398  *
399  * notes: \li
400  *
401  *	See irpmarshall.h.
402  *
403  * return: \li
404  *
405  *	0 on success, -1 on failure
406  */
407 
408 int
irp_marshall_gr(const struct group * gr,char ** buffer,size_t * len)409 irp_marshall_gr(const struct group *gr, char **buffer, size_t *len) {
410 	size_t need = 1;	/*%< for null byte */
411 	char grGid[24];
412 	const char *fieldsep = COLONSTR;
413 
414 	if (gr == NULL || len == NULL) {
415 		errno = EINVAL;
416 		return (-1);
417 	}
418 
419 	sprintf(grGid, "%ld", (long)gr->gr_gid);
420 
421 	need += strlen(gr->gr_name) + 1;
422 #ifndef MISSING_GR_PASSWD
423 	need += strlen(gr->gr_passwd) + 1;
424 #else
425 	need++;
426 #endif
427 	need += strlen(grGid) + 1;
428 	need += joinlength(gr->gr_mem) + 1;
429 
430 	if (buffer == NULL) {
431 		*len = need;
432 		return (0);
433 	}
434 
435 	if (*buffer != NULL && need > *len) {
436 		errno = EINVAL;
437 		return (-1);
438 	}
439 
440 	if (*buffer == NULL) {
441 		need += 2;		/*%< for CRLF */
442 		*buffer = memget(need);
443 		if (*buffer == NULL) {
444 			errno = ENOMEM;
445 			return (-1);
446 		}
447 
448 		*len = need;
449 	}
450 
451 	strcpy(*buffer, gr->gr_name);		strcat(*buffer, fieldsep);
452 #ifndef MISSING_GR_PASSWD
453 	strcat(*buffer, gr->gr_passwd);
454 #endif
455 	strcat(*buffer, fieldsep);
456 	strcat(*buffer, grGid);			strcat(*buffer, fieldsep);
457 	joinarray(gr->gr_mem, *buffer, COMMA) ;	strcat(*buffer, fieldsep);
458 
459 	return (0);
460 }
461 
462 /*%
463  * int irp_unmarshall_gr(struct group *gr, char *buffer)
464  *
465  * notes: \li
466  *
467  *	See irpmarshall.h
468  *
469  * return: \li
470  *
471  *	0 on success and -1 on failure.
472  *
473  */
474 
475 int
irp_unmarshall_gr(struct group * gr,char * buffer)476 irp_unmarshall_gr(struct group *gr, char *buffer) {
477 	char *p, *q;
478 	gid_t grgid;
479 	long t;
480 	char *name = NULL;
481 	char *pass = NULL;
482 	char **members = NULL;
483 	char tmpbuf[24];
484 	char *tb;
485 	char fieldsep = ':';
486 	int myerrno = EINVAL;
487 
488 	if (gr == NULL || buffer == NULL) {
489 		errno = EINVAL;
490 		return (-1);
491 	}
492 
493 	p = buffer;
494 
495 	/* gr_name field */
496 	name = NULL;
497 	if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
498 		goto error;
499 	}
500 
501 
502 	/* gr_passwd field */
503 	pass = NULL;
504 	if (getfield(&pass, 0, &p, fieldsep) == NULL) {
505 		goto error;
506 	}
507 
508 
509 	/* gr_gid field */
510 	tb = tmpbuf;
511 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
512 	    strlen(tb) == 0U) {
513 		goto error;
514 	}
515 	t = strtol(tmpbuf, &tb, 10);
516 	if (*tb) {
517 		goto error;	/*%< junk in value */
518 	}
519 	grgid = (gid_t)t;
520 	if ((long) grgid != t) {	/*%< value must have been too big. */
521 		goto error;
522 	}
523 
524 
525 	/* gr_mem field. Member names are separated by commas */
526 	q = strchr(p, fieldsep);
527 	if (q == NULL) {
528 		goto error;
529 	}
530 	members = splitarray(p, q, COMMA);
531 	if (members == NULL) {
532 		myerrno = errno;
533 		goto error;
534 	}
535 	p = q + 1;
536 
537 
538 	gr->gr_name = name;
539 #ifndef MISSING_GR_PASSWD
540 	gr->gr_passwd = pass;
541 #endif
542 	gr->gr_gid = grgid;
543 	gr->gr_mem = members;
544 
545 	return (0);
546 
547  error:
548 	errno = myerrno;
549 
550 	if (name != NULL) free(name);
551 	if (pass != NULL) free(pass);
552 
553 	return (-1);
554 }
555 
556 
557 /* ------------------------- struct group ------------------------- */
558 
559 
560 
561 
562 /* +++++++++++++++++++++++++ struct servent +++++++++++++++++++++++++ */
563 
564 /*%
565  * int irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len)
566  *
567  * notes: \li
568  *
569  *	See irpmarshall.h
570  *
571  * return: \li
572  *
573  *	0 on success, -1 on failure.
574  *
575  */
576 
577 int
irp_marshall_sv(const struct servent * sv,char ** buffer,size_t * len)578 irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len) {
579 	size_t need = 1;	/*%< for null byte */
580 	char svPort[24];
581 	const char *fieldsep = COLONSTR;
582 	short realport;
583 
584 	if (sv == NULL || len == NULL) {
585 		errno = EINVAL;
586 		return (-1);
587 	}
588 
589 	/* the int s_port field is actually a short in network order. We
590 	   want host order to make the marshalled data look correct */
591 	realport = ntohs((short)sv->s_port);
592 	sprintf(svPort, "%d", realport);
593 
594 	need += strlen(sv->s_name) + 1;
595 	need += joinlength(sv->s_aliases) + 1;
596 	need += strlen(svPort) + 1;
597 	need += strlen(sv->s_proto) + 1;
598 
599 	if (buffer == NULL) {
600 		*len = need;
601 		return (0);
602 	}
603 
604 	if (*buffer != NULL && need > *len) {
605 		errno = EINVAL;
606 		return (-1);
607 	}
608 
609 	if (*buffer == NULL) {
610 		need += 2;		/*%< for CRLF */
611 		*buffer = memget(need);
612 		if (*buffer == NULL) {
613 			errno = ENOMEM;
614 			return (-1);
615 		}
616 
617 		*len = need;
618 	}
619 
620 	strcpy(*buffer, sv->s_name);		strcat(*buffer, fieldsep);
621 	joinarray(sv->s_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
622 	strcat(*buffer, svPort);		strcat(*buffer, fieldsep);
623 	strcat(*buffer, sv->s_proto);		strcat(*buffer, fieldsep);
624 
625 	return (0);
626 }
627 
628 /*%
629  * int irp_unmarshall_sv(struct servent *sv, char *buffer)
630  *
631  * notes: \li
632  *
633  *	See irpmarshall.h
634  *
635  * return: \li
636  *
637  *	0 on success, -1 on failure.
638  *
639  */
640 
641 int
irp_unmarshall_sv(struct servent * sv,char * buffer)642 irp_unmarshall_sv(struct servent *sv, char *buffer) {
643 	char *p, *q;
644 	short svport;
645 	long t;
646 	char *name = NULL;
647 	char *proto = NULL;
648 	char **aliases = NULL;
649 	char tmpbuf[24];
650 	char *tb;
651 	char fieldsep = ':';
652 	int myerrno = EINVAL;
653 
654 	if (sv == NULL || buffer == NULL)
655 		return (-1);
656 
657 	p = buffer;
658 
659 
660 	/* s_name field */
661 	name = NULL;
662 	if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
663 		goto error;
664 	}
665 
666 
667 	/* s_aliases field */
668 	q = strchr(p, fieldsep);
669 	if (q == NULL) {
670 		goto error;
671 	}
672 	aliases = splitarray(p, q, COMMA);
673 	if (aliases == NULL) {
674 		myerrno = errno;
675 		goto error;
676 	}
677 	p = q + 1;
678 
679 
680 	/* s_port field */
681 	tb = tmpbuf;
682 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
683 	    strlen(tb) == 0U) {
684 		goto error;
685 	}
686 	t = strtol(tmpbuf, &tb, 10);
687 	if (*tb) {
688 		goto error;	/*%< junk in value */
689 	}
690 	svport = (short)t;
691 	if ((long) svport != t) {	/*%< value must have been too big. */
692 		goto error;
693 	}
694 	svport = htons(svport);
695 
696 	/* s_proto field */
697 	proto = NULL;
698 	if (getfield(&proto, 0, &p, fieldsep) == NULL) {
699 		goto error;
700 	}
701 
702 	sv->s_name = name;
703 	sv->s_aliases = aliases;
704 	sv->s_port = svport;
705 	sv->s_proto = proto;
706 
707 	return (0);
708 
709  error:
710 	errno = myerrno;
711 
712 	if (name != NULL) free(name);
713 	if (proto != NULL) free(proto);
714 	free_array(aliases, 0);
715 
716 	return (-1);
717 }
718 
719 
720 /* ------------------------- struct servent ------------------------- */
721 
722 /* +++++++++++++++++++++++++ struct protoent +++++++++++++++++++++++++ */
723 
724 /*%
725  * int irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len)
726  *
727  * notes: \li
728  *
729  *	See irpmarshall.h
730  *
731  * return: \li
732  *
733  *	0 on success and -1 on failure.
734  *
735  */
736 
737 int
irp_marshall_pr(struct protoent * pr,char ** buffer,size_t * len)738 irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len) {
739 	size_t need = 1;	/*%< for null byte */
740 	char prProto[24];
741 	const char *fieldsep = COLONSTR;
742 
743 	if (pr == NULL || len == NULL) {
744 		errno = EINVAL;
745 		return (-1);
746 	}
747 
748 	sprintf(prProto, "%d", (int)pr->p_proto);
749 
750 	need += strlen(pr->p_name) + 1;
751 	need += joinlength(pr->p_aliases) + 1;
752 	need += strlen(prProto) + 1;
753 
754 	if (buffer == NULL) {
755 		*len = need;
756 		return (0);
757 	}
758 
759 	if (*buffer != NULL && need > *len) {
760 		errno = EINVAL;
761 		return (-1);
762 	}
763 
764 	if (*buffer == NULL) {
765 		need += 2;		/*%< for CRLF */
766 		*buffer = memget(need);
767 		if (*buffer == NULL) {
768 			errno = ENOMEM;
769 			return (-1);
770 		}
771 
772 		*len = need;
773 	}
774 
775 	strcpy(*buffer, pr->p_name);		strcat(*buffer, fieldsep);
776 	joinarray(pr->p_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
777 	strcat(*buffer, prProto);		strcat(*buffer, fieldsep);
778 
779 	return (0);
780 
781 }
782 
783 /*%
784  * int irp_unmarshall_pr(struct protoent *pr, char *buffer)
785  *
786  * notes: \li
787  *
788  *	See irpmarshall.h
789  *
790  * return: \li
791  *
792  *	0 on success, -1 on failure
793  *
794  */
795 
irp_unmarshall_pr(struct protoent * pr,char * buffer)796 int irp_unmarshall_pr(struct protoent *pr, char *buffer) {
797 	char *p, *q;
798 	int prproto;
799 	long t;
800 	char *name = NULL;
801 	char **aliases = NULL;
802 	char tmpbuf[24];
803 	char *tb;
804 	char fieldsep = ':';
805 	int myerrno = EINVAL;
806 
807 	if (pr == NULL || buffer == NULL) {
808 		errno = EINVAL;
809 		return (-1);
810 	}
811 
812 	p = buffer;
813 
814 	/* p_name field */
815 	name = NULL;
816 	if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
817 		goto error;
818 	}
819 
820 
821 	/* p_aliases field */
822 	q = strchr(p, fieldsep);
823 	if (q == NULL) {
824 		goto error;
825 	}
826 	aliases = splitarray(p, q, COMMA);
827 	if (aliases == NULL) {
828 		myerrno = errno;
829 		goto error;
830 	}
831 	p = q + 1;
832 
833 
834 	/* p_proto field */
835 	tb = tmpbuf;
836 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
837 	    strlen(tb) == 0U) {
838 		goto error;
839 	}
840 	t = strtol(tmpbuf, &tb, 10);
841 	if (*tb) {
842 		goto error;	/*%< junk in value */
843 	}
844 	prproto = (int)t;
845 	if ((long) prproto != t) {	/*%< value must have been too big. */
846 		goto error;
847 	}
848 
849 	pr->p_name = name;
850 	pr->p_aliases = aliases;
851 	pr->p_proto = prproto;
852 
853 	return (0);
854 
855  error:
856 	errno = myerrno;
857 
858 	if (name != NULL) free(name);
859 	free_array(aliases, 0);
860 
861 	return (-1);
862 }
863 
864 /* ------------------------- struct protoent ------------------------- */
865 
866 
867 
868 /* +++++++++++++++++++++++++ struct hostent +++++++++++++++++++++++++ */
869 
870 /*%
871  * int irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len)
872  *
873  * notes: \li
874  *
875  *	See irpmarshall.h.
876  *
877  * return: \li
878  *
879  *	0 on success, -1 on failure.
880  *
881  */
882 
883 int
irp_marshall_ho(struct hostent * ho,char ** buffer,size_t * len)884 irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len) {
885 	size_t need = 1;	/*%< for null byte */
886 	char hoaddrtype[24];
887 	char holength[24];
888 	char **av;
889 	char *p;
890 	int addrlen;
891 	int malloced = 0;
892 	size_t remlen;
893 	const char *fieldsep = "@";
894 
895 	if (ho == NULL || len == NULL) {
896 		errno = EINVAL;
897 		return (-1);
898 	}
899 
900 	switch(ho->h_addrtype) {
901 	case AF_INET:
902 		strcpy(hoaddrtype, "AF_INET");
903 		break;
904 
905 	case AF_INET6:
906 		strcpy(hoaddrtype, "AF_INET6");
907 		break;
908 
909 	default:
910 		errno = EINVAL;
911 		return (-1);
912 	}
913 
914 	sprintf(holength, "%d", ho->h_length);
915 
916 	need += strlen(ho->h_name) + 1;
917 	need += joinlength(ho->h_aliases) + 1;
918 	need += strlen(hoaddrtype) + 1;
919 	need += strlen(holength) + 1;
920 
921 	/* we determine an upper bound on the string length needed, not an
922 	   exact length. */
923 	addrlen = (ho->h_addrtype == AF_INET ? 16 : 46) ; /*%< XX other AF's?? */
924 	for (av = ho->h_addr_list; av != NULL && *av != NULL ; av++)
925 		need += addrlen;
926 
927 	if (buffer == NULL) {
928 		*len = need;
929 		return (0);
930 	}
931 
932 	if (*buffer != NULL && need > *len) {
933 		errno = EINVAL;
934 		return (-1);
935 	}
936 
937 	if (*buffer == NULL) {
938 		need += 2;		/*%< for CRLF */
939 		*buffer = memget(need);
940 		if (*buffer == NULL) {
941 			errno = ENOMEM;
942 			return (-1);
943 		}
944 
945 		*len = need;
946 		malloced = 1;
947 	}
948 
949 	strcpy(*buffer, ho->h_name);		strcat(*buffer, fieldsep);
950 	joinarray(ho->h_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
951 	strcat(*buffer, hoaddrtype);		strcat(*buffer, fieldsep);
952 	strcat(*buffer, holength);		strcat(*buffer, fieldsep);
953 
954 	p = *buffer + strlen(*buffer);
955 	remlen = need - strlen(*buffer);
956 	for (av = ho->h_addr_list ; av != NULL && *av != NULL ; av++) {
957 		if (inet_ntop(ho->h_addrtype, *av, p, remlen) == NULL) {
958 			goto error;
959 		}
960 		if (*(av + 1) != NULL)
961 			strcat(p, COMMASTR);
962 		remlen -= strlen(p);
963 		p += strlen(p);
964 	}
965 	strcat(*buffer, fieldsep);
966 
967 	return (0);
968 
969  error:
970 	if (malloced) {
971 		memput(*buffer, need);
972 	}
973 
974 	return (-1);
975 }
976 
977 /*%
978  * int irp_unmarshall_ho(struct hostent *ho, char *buffer)
979  *
980  * notes: \li
981  *
982  *	See irpmarshall.h.
983  *
984  * return: \li
985  *
986  *	0 on success, -1 on failure.
987  *
988  */
989 
990 int
irp_unmarshall_ho(struct hostent * ho,char * buffer)991 irp_unmarshall_ho(struct hostent *ho, char *buffer) {
992 	char *p, *q, *r;
993 	int hoaddrtype;
994 	int holength;
995 	long t;
996 	char *name;
997 	char **aliases = NULL;
998 	char **hohaddrlist = NULL;
999 	size_t hoaddrsize;
1000 	char tmpbuf[24];
1001 	char *tb;
1002 	char **alist;
1003 	int addrcount;
1004 	char fieldsep = '@';
1005 	int myerrno = EINVAL;
1006 
1007 	if (ho == NULL || buffer == NULL) {
1008 		errno = EINVAL;
1009 		return (-1);
1010 	}
1011 
1012 	p = buffer;
1013 
1014 	/* h_name field */
1015 	name = NULL;
1016 	if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
1017 		goto error;
1018 	}
1019 
1020 
1021 	/* h_aliases field */
1022 	q = strchr(p, fieldsep);
1023 	if (q == NULL) {
1024 		goto error;
1025 	}
1026 	aliases = splitarray(p, q, COMMA);
1027 	if (aliases == NULL) {
1028 		myerrno = errno;
1029 		goto error;
1030 	}
1031 	p = q + 1;
1032 
1033 
1034 	/* h_addrtype field */
1035 	tb = tmpbuf;
1036 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1037 	    strlen(tb) == 0U) {
1038 		goto error;
1039 	}
1040 	if (strcmp(tmpbuf, "AF_INET") == 0)
1041 		hoaddrtype = AF_INET;
1042 	else if (strcmp(tmpbuf, "AF_INET6") == 0)
1043 		hoaddrtype = AF_INET6;
1044 	else
1045 		goto error;
1046 
1047 
1048 	/* h_length field */
1049 	tb = tmpbuf;
1050 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1051 	    strlen(tb) == 0U) {
1052 		goto error;
1053 	}
1054 	t = strtol(tmpbuf, &tb, 10);
1055 	if (*tb) {
1056 		goto error;	/*%< junk in value */
1057 	}
1058 	holength = (int)t;
1059 	if ((long) holength != t) {	/*%< value must have been too big. */
1060 		goto error;
1061 	}
1062 
1063 
1064 	/* h_addr_list field */
1065 	q = strchr(p, fieldsep);
1066 	if (q == NULL)
1067 		goto error;
1068 
1069 	/* count how many addresss are in there */
1070 	if (q > p + 1) {
1071 		for (addrcount = 1, r = p ; r != q ; r++) {
1072 			if (*r == COMMA)
1073 				addrcount++;
1074 		}
1075 	} else {
1076 		addrcount = 0;
1077 	}
1078 
1079 	hoaddrsize = (addrcount + 1) * sizeof (char *);
1080 	hohaddrlist = malloc(hoaddrsize);
1081 	if (hohaddrlist == NULL) {
1082 		myerrno = ENOMEM;
1083 		goto error;
1084 	}
1085 
1086 	memset(hohaddrlist, 0x0, hoaddrsize);
1087 
1088 	alist = hohaddrlist;
1089 	for (t = 0, r = p ; r != q ; p = r + 1, t++) {
1090 		char saved;
1091 		while (r != q && *r != COMMA) r++;
1092 		saved = *r;
1093 		*r = 0x0;
1094 
1095 		alist[t] = malloc(hoaddrtype == AF_INET ? 4 : 16);
1096 		if (alist[t] == NULL) {
1097 			myerrno = ENOMEM;
1098 			goto error;
1099 		}
1100 
1101 		if (inet_pton(hoaddrtype, p, alist[t]) == -1)
1102 			goto error;
1103 		*r = saved;
1104 	}
1105 	alist[t] = NULL;
1106 
1107 	ho->h_name = name;
1108 	ho->h_aliases = aliases;
1109 	ho->h_addrtype = hoaddrtype;
1110 	ho->h_length = holength;
1111 	ho->h_addr_list = hohaddrlist;
1112 
1113 	return (0);
1114 
1115  error:
1116 	errno = myerrno;
1117 
1118 	if (name != NULL) free(name);
1119 	free_array(hohaddrlist, 0);
1120 	free_array(aliases, 0);
1121 
1122 	return (-1);
1123 }
1124 
1125 /* ------------------------- struct hostent------------------------- */
1126 
1127 
1128 
1129 /* +++++++++++++++++++++++++ struct netgrp +++++++++++++++++++++++++ */
1130 
1131 /*%
1132  * int irp_marshall_ng(const char *host, const char *user,
1133  *		       const char *domain, char *buffer, size_t *len)
1134  *
1135  * notes: \li
1136  *
1137  *	See note for irp_marshall_ng_start
1138  *
1139  * return: \li
1140  *
1141  *	0 on success, 0 on failure.
1142  *
1143  */
1144 
1145 int
irp_marshall_ng(const char * host,const char * user,const char * domain,char ** buffer,size_t * len)1146 irp_marshall_ng(const char *host, const char *user, const char *domain,
1147 		char **buffer, size_t *len) {
1148 	size_t need = 1; /*%< for nul byte */
1149 	const char *fieldsep = ",";
1150 
1151 	if (len == NULL) {
1152 		errno = EINVAL;
1153 		return (-1);
1154 	}
1155 
1156 	need += 4;		       /*%< two parens and two commas */
1157 	need += (host == NULL ? 0 : strlen(host));
1158 	need += (user == NULL ? 0 : strlen(user));
1159 	need += (domain == NULL ? 0 : strlen(domain));
1160 
1161 	if (buffer == NULL) {
1162 		*len = need;
1163 		return (0);
1164 	} else if (*buffer != NULL && need > *len) {
1165 		errno = EINVAL;
1166 		return (-1);
1167 	}
1168 
1169 	if (*buffer == NULL) {
1170 		need += 2;		/*%< for CRLF */
1171 		*buffer = memget(need);
1172 		if (*buffer == NULL) {
1173 			errno = ENOMEM;
1174 			return (-1);
1175 		}
1176 
1177 		*len = need;
1178 	}
1179 
1180 	(*buffer)[0] = '(';
1181 	(*buffer)[1] = '\0';
1182 
1183 	if (host != NULL)
1184 		strcat(*buffer, host);
1185 	strcat(*buffer, fieldsep);
1186 
1187 	if (user != NULL)
1188 		strcat(*buffer, user);
1189 	strcat(*buffer, fieldsep);
1190 
1191 	if (domain != NULL)
1192 		strcat(*buffer, domain);
1193 	strcat(*buffer, ")");
1194 
1195 	return (0);
1196 }
1197 
1198 
1199 
1200 /* ---------- */
1201 
1202 /*%
1203  * int irp_unmarshall_ng(const char **host, const char **user,
1204  *			 const char **domain, char *buffer)
1205  *
1206  * notes: \li
1207  *
1208  *	Unpacks the BUFFER into 3 character arrays it allocates and assigns
1209  *	to *HOST, *USER and *DOMAIN. If any field of the value is empty,
1210  *	then the corresponding paramater value will be set to NULL.
1211  *
1212  * return: \li
1213  *
1214  *	0 on success and -1 on failure.
1215  */
1216 
1217 int
irp_unmarshall_ng(const char ** hostp,const char ** userp,const char ** domainp,char * buffer)1218 irp_unmarshall_ng(const char **hostp, const char **userp, const char **domainp,
1219 		  char *buffer)
1220 {
1221 	char *p, *q;
1222 	char fieldsep = ',';
1223 	int myerrno = EINVAL;
1224 	char *host, *user, *domain;
1225 
1226 	if (userp == NULL || hostp == NULL ||
1227 	    domainp == NULL || buffer == NULL) {
1228 		errno = EINVAL;
1229 		return (-1);
1230 	}
1231 
1232 	host = user = domain = NULL;
1233 
1234 	p = buffer;
1235 	while (isspace((unsigned char)*p)) {
1236 		p++;
1237 	}
1238 	if (*p != '(') {
1239 		goto error;
1240 	}
1241 
1242 	q = p + 1;
1243 	while (*q && *q != fieldsep)
1244 		q++;
1245 	if (!*q) {
1246 		goto error;
1247 	} else if (q > p + 1) {
1248 		host = strndup(p, q - p);
1249 	}
1250 
1251 	p = q + 1;
1252 	if (!*p) {
1253 		goto error;
1254 	} else if (*p != fieldsep) {
1255 		q = p + 1;
1256 		while (*q && *q != fieldsep)
1257 			q++;
1258 		if (!*q) {
1259 			goto error;
1260 		}
1261 		user = strndup(p, q - p);
1262 	} else {
1263 		p++;
1264 	}
1265 
1266 	if (!*p) {
1267 		goto error;
1268 	} else if (*p != ')') {
1269 		q = p + 1;
1270 		while (*q && *q != ')')
1271 			q++;
1272 		if (!*q) {
1273 			goto error;
1274 		}
1275 		domain = strndup(p, q - p);
1276 	}
1277 	*hostp = host;
1278 	*userp = user;
1279 	*domainp = domain;
1280 
1281 	return (0);
1282 
1283  error:
1284 	errno = myerrno;
1285 
1286 	if (host != NULL) free(host);
1287 	if (user != NULL) free(user);
1288 
1289 	return (-1);
1290 }
1291 
1292 /* ------------------------- struct netgrp ------------------------- */
1293 
1294 
1295 
1296 
1297 /* +++++++++++++++++++++++++ struct nwent +++++++++++++++++++++++++ */
1298 
1299 /*%
1300  * int irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len)
1301  *
1302  * notes: \li
1303  *
1304  *	See at top.
1305  *
1306  * return: \li
1307  *
1308  *	0 on success and -1 on failure.
1309  *
1310  */
1311 
1312 int
irp_marshall_nw(struct nwent * ne,char ** buffer,size_t * len)1313 irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len) {
1314 	size_t need = 1;	/*%< for null byte */
1315 	char nAddrType[24];
1316 	char nNet[MAXPADDRSIZE];
1317 	const char *fieldsep = COLONSTR;
1318 
1319 	if (ne == NULL || len == NULL) {
1320 		return (-1);
1321 	}
1322 
1323 	strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype));
1324 
1325 	if (inet_net_ntop(ne->n_addrtype, ne->n_addr, ne->n_length,
1326 			  nNet, sizeof nNet) == NULL) {
1327 		return (-1);
1328 	}
1329 
1330 
1331 	need += strlen(ne->n_name) + 1;
1332 	need += joinlength(ne->n_aliases) + 1;
1333 	need += strlen(nAddrType) + 1;
1334 	need += strlen(nNet) + 1;
1335 
1336 	if (buffer == NULL) {
1337 		*len = need;
1338 		return (0);
1339 	}
1340 
1341 	if (*buffer != NULL && need > *len) {
1342 		errno = EINVAL;
1343 		return (-1);
1344 	}
1345 
1346 	if (*buffer == NULL) {
1347 		need += 2;		/*%< for CRLF */
1348 		*buffer = memget(need);
1349 		if (*buffer == NULL) {
1350 			errno = ENOMEM;
1351 			return (-1);
1352 		}
1353 
1354 		*len = need;
1355 	}
1356 
1357 	strcpy(*buffer, ne->n_name);		strcat(*buffer, fieldsep);
1358 	joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep);
1359 	strcat(*buffer, nAddrType);		strcat(*buffer, fieldsep);
1360 	strcat(*buffer, nNet);			strcat(*buffer, fieldsep);
1361 
1362 	return (0);
1363 }
1364 
1365 /*%
1366  * int irp_unmarshall_nw(struct nwent *ne, char *buffer)
1367  *
1368  * notes: \li
1369  *
1370  *	See note up top.
1371  *
1372  * return: \li
1373  *
1374  *	0 on success and -1 on failure.
1375  *
1376  */
1377 
1378 int
irp_unmarshall_nw(struct nwent * ne,char * buffer)1379 irp_unmarshall_nw(struct nwent *ne, char *buffer) {
1380 	char *p, *q;
1381 	int naddrtype;
1382 	long nnet;
1383 	int bits;
1384 	char *name = NULL;
1385 	char **aliases = NULL;
1386 	char tmpbuf[24];
1387 	char *tb;
1388 	char fieldsep = ':';
1389 	int myerrno = EINVAL;
1390 
1391 	if (ne == NULL || buffer == NULL) {
1392 		goto error;
1393 	}
1394 
1395 	p = buffer;
1396 
1397 	/* n_name field */
1398 	name = NULL;
1399 	if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
1400 		goto error;
1401 	}
1402 
1403 
1404 	/* n_aliases field. Aliases are separated by commas */
1405 	q = strchr(p, fieldsep);
1406 	if (q == NULL) {
1407 		goto error;
1408 	}
1409 	aliases = splitarray(p, q, COMMA);
1410 	if (aliases == NULL) {
1411 		myerrno = errno;
1412 		goto error;
1413 	}
1414 	p = q + 1;
1415 
1416 
1417 	/* h_addrtype field */
1418 	tb = tmpbuf;
1419 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1420 	    strlen(tb) == 0U) {
1421 		goto error;
1422 	}
1423 	if (strcmp(tmpbuf, "AF_INET") == 0)
1424 		naddrtype = AF_INET;
1425 	else if (strcmp(tmpbuf, "AF_INET6") == 0)
1426 		naddrtype = AF_INET6;
1427 	else
1428 		goto error;
1429 
1430 
1431 	/* n_net field */
1432 	tb = tmpbuf;
1433 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1434 	    strlen(tb) == 0U) {
1435 		goto error;
1436 	}
1437 	nnet = 0;
1438 	bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet);
1439 	if (bits < 0) {
1440 		goto error;
1441 	}
1442 
1443 	/* nnet = ntohl(nnet); */ /* keep in network order for nwent */
1444 
1445 	ne->n_name = name;
1446 	ne->n_aliases = aliases;
1447 	ne->n_addrtype = naddrtype;
1448 	ne->n_length = bits;
1449 	ne->n_addr = malloc(sizeof nnet);
1450 	if (ne->n_addr == NULL) {
1451 		goto error;
1452 	}
1453 
1454 	memcpy(ne->n_addr, &nnet, sizeof nnet);
1455 
1456 	return (0);
1457 
1458  error:
1459 	errno = myerrno;
1460 
1461 	if (name != NULL) free(name);
1462 	free_array(aliases, 0);
1463 
1464 	return (-1);
1465 }
1466 
1467 
1468 /* ------------------------- struct nwent ------------------------- */
1469 
1470 
1471 /* +++++++++++++++++++++++++ struct netent +++++++++++++++++++++++++ */
1472 
1473 /*%
1474  * int irp_marshall_ne(struct netent *ne, char **buffer, size_t *len)
1475  *
1476  * notes: \li
1477  *
1478  *	See at top.
1479  *
1480  * return: \li
1481  *
1482  *	0 on success and -1 on failure.
1483  *
1484  */
1485 
1486 int
irp_marshall_ne(struct netent * ne,char ** buffer,size_t * len)1487 irp_marshall_ne(struct netent *ne, char **buffer, size_t *len) {
1488 	size_t need = 1;	/*%< for null byte */
1489 	char nAddrType[24];
1490 	char nNet[MAXPADDRSIZE];
1491 	const char *fieldsep = COLONSTR;
1492 	long nval;
1493 
1494 	if (ne == NULL || len == NULL) {
1495 		return (-1);
1496 	}
1497 
1498 	strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype));
1499 
1500 	nval = htonl(ne->n_net);
1501 	if (inet_ntop(ne->n_addrtype, &nval, nNet, sizeof nNet) == NULL) {
1502 		return (-1);
1503 	}
1504 
1505 	need += strlen(ne->n_name) + 1;
1506 	need += joinlength(ne->n_aliases) + 1;
1507 	need += strlen(nAddrType) + 1;
1508 	need += strlen(nNet) + 1;
1509 
1510 	if (buffer == NULL) {
1511 		*len = need;
1512 		return (0);
1513 	}
1514 
1515 	if (*buffer != NULL && need > *len) {
1516 		errno = EINVAL;
1517 		return (-1);
1518 	}
1519 
1520 	if (*buffer == NULL) {
1521 		need += 2;		/*%< for CRLF */
1522 		*buffer = memget(need);
1523 		if (*buffer == NULL) {
1524 			errno = ENOMEM;
1525 			return (-1);
1526 		}
1527 
1528 		*len = need;
1529 	}
1530 
1531 	strcpy(*buffer, ne->n_name);		strcat(*buffer, fieldsep);
1532 	joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep);
1533 	strcat(*buffer, nAddrType);		strcat(*buffer, fieldsep);
1534 	strcat(*buffer, nNet);			strcat(*buffer, fieldsep);
1535 
1536 	return (0);
1537 }
1538 
1539 /*%
1540  * int irp_unmarshall_ne(struct netent *ne, char *buffer)
1541  *
1542  * notes: \li
1543  *
1544  *	See note up top.
1545  *
1546  * return: \li
1547  *
1548  *	0 on success and -1 on failure.
1549  *
1550  */
1551 
1552 int
irp_unmarshall_ne(struct netent * ne,char * buffer)1553 irp_unmarshall_ne(struct netent *ne, char *buffer) {
1554 	char *p, *q;
1555 	int naddrtype;
1556 	long nnet;
1557 	int bits;
1558 	char *name = NULL;
1559 	char **aliases = NULL;
1560 	char tmpbuf[24];
1561 	char *tb;
1562 	char fieldsep = ':';
1563 	int myerrno = EINVAL;
1564 
1565 	if (ne == NULL || buffer == NULL) {
1566 		goto error;
1567 	}
1568 
1569 	p = buffer;
1570 
1571 	/* n_name field */
1572 	name = NULL;
1573 	if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
1574 		goto error;
1575 	}
1576 
1577 
1578 	/* n_aliases field. Aliases are separated by commas */
1579 	q = strchr(p, fieldsep);
1580 	if (q == NULL) {
1581 		goto error;
1582 	}
1583 	aliases = splitarray(p, q, COMMA);
1584 	if (aliases == NULL) {
1585 		myerrno = errno;
1586 		goto error;
1587 	}
1588 	p = q + 1;
1589 
1590 
1591 	/* h_addrtype field */
1592 	tb = tmpbuf;
1593 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1594 	    strlen(tb) == 0U) {
1595 		goto error;
1596 	}
1597 	if (strcmp(tmpbuf, "AF_INET") == 0)
1598 		naddrtype = AF_INET;
1599 	else if (strcmp(tmpbuf, "AF_INET6") == 0)
1600 		naddrtype = AF_INET6;
1601 	else
1602 		goto error;
1603 
1604 
1605 	/* n_net field */
1606 	tb = tmpbuf;
1607 	if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
1608 	    strlen(tb) == 0U) {
1609 		goto error;
1610 	}
1611 	bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet);
1612 	if (bits < 0) {
1613 		goto error;
1614 	}
1615 	nnet = ntohl(nnet);
1616 
1617 	ne->n_name = name;
1618 	ne->n_aliases = aliases;
1619 	ne->n_addrtype = naddrtype;
1620 	ne->n_net = nnet;
1621 
1622 	return (0);
1623 
1624  error:
1625 	errno = myerrno;
1626 
1627 	if (name != NULL) free(name);
1628 	free_array(aliases, 0);
1629 
1630 	return (-1);
1631 }
1632 
1633 
1634 /* ------------------------- struct netent ------------------------- */
1635 
1636 
1637 /* =========================================================================== */
1638 
1639 /*%
1640  * static char ** splitarray(const char *buffer, const char *buffend, char delim)
1641  *
1642  * notes: \li
1643  *
1644  *	Split a delim separated astring. Not allowed
1645  *	to have two delims next to each other. BUFFER points to begining of
1646  *	string, BUFFEND points to one past the end of the string
1647  *	(i.e. points at where the null byte would be if null
1648  *	terminated).
1649  *
1650  * return: \li
1651  *
1652  *	Returns a malloced array of pointers, each pointer pointing to a
1653  *	malloced string. If BUFEER is an empty string, then return values is
1654  *	array of 1 pointer that is NULL. Returns NULL on failure.
1655  *
1656  */
1657 
1658 static char **
splitarray(const char * buffer,const char * buffend,char delim)1659 splitarray(const char *buffer, const char *buffend, char delim) {
1660 	const char *p, *q;
1661 	int count = 0;
1662 	char **arr = NULL;
1663 	char **aptr;
1664 
1665 	if (buffend < buffer)
1666 		return (NULL);
1667 	else if (buffend > buffer && *buffer == delim)
1668 		return (NULL);
1669 	else if (buffend > buffer && *(buffend - 1) == delim)
1670 		return (NULL);
1671 
1672 	/* count the number of field and make sure none are empty */
1673 	if (buffend > buffer + 1) {
1674 		for (count = 1, q = buffer ; q != buffend ; q++) {
1675 			if (*q == delim) {
1676 				if (q > buffer && (*(q - 1) == delim)) {
1677 					errno = EINVAL;
1678 					return (NULL);
1679 				}
1680 				count++;
1681 			}
1682 		}
1683 	}
1684 
1685 	if (count > 0) {
1686 		count++ ;		/*%< for NULL at end */
1687 		aptr = arr = malloc(count * sizeof (char *));
1688 		if (aptr == NULL) {
1689 			 errno = ENOMEM;
1690 			 return (NULL);
1691 		 }
1692 
1693 		memset(arr, 0x0, count * sizeof (char *));
1694 		for (p = buffer ; p < buffend ; p++) {
1695 			for (q = p ; *q != delim && q != buffend ; q++)
1696 				/* nothing */;
1697 			*aptr = strndup(p, q - p);
1698 
1699 			p = q;
1700 			aptr++;
1701 		}
1702 		*aptr = NULL;
1703 	} else {
1704 		arr = malloc(sizeof (char *));
1705 		if (arr == NULL) {
1706 			errno = ENOMEM;
1707 			return (NULL);
1708 		}
1709 
1710 		*arr = NULL;
1711 	}
1712 
1713 	return (arr);
1714 }
1715 
1716 /*%
1717  * static size_t joinlength(char * const *argv)
1718  *
1719  * return: \li
1720  *
1721  *	the number of bytes in all the arrays pointed at
1722  *	by argv, including their null bytes(which will usually be turned
1723  *	into commas).
1724  *
1725  *
1726  */
1727 
1728 static size_t
joinlength(char * const * argv)1729 joinlength(char * const *argv) {
1730 	int len = 0;
1731 
1732 	while (argv && *argv) {
1733 		len += (strlen(*argv) + 1);
1734 		argv++;
1735 	}
1736 
1737 	return (len);
1738 }
1739 
1740 /*%
1741  * int joinarray(char * const *argv, char *buffer, char delim)
1742  *
1743  * notes: \li
1744  *
1745  *	Copy all the ARGV strings into the end of BUFFER
1746  *	separating them with DELIM.  BUFFER is assumed to have
1747  *	enough space to hold everything and to be already null-terminated.
1748  *
1749  * return: \li
1750  *
1751  *	0 unless argv or buffer is NULL.
1752  *
1753  *
1754  */
1755 
1756 static int
joinarray(char * const * argv,char * buffer,char delim)1757 joinarray(char * const *argv, char *buffer, char delim) {
1758 	char * const *p;
1759 	char sep[2];
1760 
1761 	if (argv == NULL || buffer == NULL) {
1762 		errno = EINVAL;
1763 		return (-1);
1764 	}
1765 
1766 	sep[0] = delim;
1767 	sep[1] = 0x0;
1768 
1769 	for (p = argv ; *p != NULL ; p++) {
1770 		strcat(buffer, *p);
1771 		if (*(p + 1) != NULL) {
1772 			strcat(buffer, sep);
1773 		}
1774 	}
1775 
1776 	return (0);
1777 }
1778 
1779 /*%
1780  * static char * getfield(char **res, size_t reslen, char **ptr, char delim)
1781  *
1782  * notes: \li
1783  *
1784  *	Stores in *RES, which is a buffer of length RESLEN, a
1785  *	copy of the bytes from *PTR up to and including the first
1786  *	instance of DELIM. If *RES is NULL, then it will be
1787  *	assigned a malloced buffer to hold the copy. *PTR is
1788  *	modified to point at the found delimiter.
1789  *
1790  * return: \li
1791  *
1792  *	If there was no delimiter, then NULL is returned,
1793  *	otherewise *RES is returned.
1794  *
1795  */
1796 
1797 static char *
getfield(char ** res,size_t reslen,char ** ptr,char delim)1798 getfield(char **res, size_t reslen, char **ptr, char delim) {
1799 	char *q;
1800 
1801 	if (res == NULL || ptr == NULL || *ptr == NULL) {
1802 		errno = EINVAL;
1803 		return (NULL);
1804 	}
1805 
1806 	q = strchr(*ptr, delim);
1807 
1808 	if (q == NULL) {
1809 		errno = EINVAL;
1810 		return (NULL);
1811 	} else {
1812 		if (*res == NULL) {
1813 			*res = strndup(*ptr, q - *ptr);
1814 		} else {
1815 			if ((size_t)(q - *ptr + 1) > reslen) { /*%< to big for res */
1816 				errno = EINVAL;
1817 				return (NULL);
1818 			} else {
1819 				strncpy(*res, *ptr, q - *ptr);
1820 				(*res)[q - *ptr] = 0x0;
1821 			}
1822 		}
1823 		*ptr = q + 1;
1824 	}
1825 
1826 	return (*res);
1827 }
1828 
1829 
1830 
1831 
1832 
1833 #ifndef HAVE_STRNDUP
1834 /*
1835  * static char * strndup(const char *str, size_t len)
1836  *
1837  * notes: \li
1838  *
1839  *	like strdup, except do len bytes instead of the whole string. Always
1840  *	null-terminates.
1841  *
1842  * return: \li
1843  *
1844  *	The newly malloced string.
1845  *
1846  */
1847 
1848 static char *
strndup(const char * str,size_t len)1849 strndup(const char *str, size_t len) {
1850 	char *p = malloc(len + 1);
1851 
1852 	if (p == NULL)
1853 		return (NULL);
1854 	strncpy(p, str, len);
1855 	p[len] = 0x0;
1856 	return (p);
1857 }
1858 #endif
1859 
1860 #if WANT_MAIN
1861 
1862 /*%
1863  * static int strcmp_nws(const char *a, const char *b)
1864  *
1865  * notes: \li
1866  *
1867  *	do a strcmp, except uneven lengths of whitespace compare the same
1868  *
1869  * return: \li
1870  *
1871  */
1872 
1873 static int
strcmp_nws(const char * a,const char * b)1874 strcmp_nws(const char *a, const char *b) {
1875 	while (*a && *b) {
1876 		if (isspace(*a) && isspace(*b)) {
1877 			do {
1878 				a++;
1879 			} while (isspace(*a));
1880 			do {
1881 				b++;
1882 			} while (isspace(*b));
1883 		}
1884 		if (*a < *b)
1885 			return (-1);
1886 		else if (*a > *b)
1887 			return (1);
1888 
1889 		a++;
1890 		b++;;
1891 	}
1892 
1893 	if (*a == *b)
1894 		return (0);
1895 	else if (*a > *b)
1896 		return (1);
1897 	else
1898 		return (-1);
1899 }
1900 
1901 #endif
1902 
1903 /*%
1904  * static void free_array(char **argv, size_t entries)
1905  *
1906  * notes: \li
1907  *
1908  *	Free argv and each of the pointers inside it. The end of
1909  *	the array is when a NULL pointer is found inside. If
1910  *	entries is > 0, then NULL pointers inside the array do
1911  *	not indicate the end of the array.
1912  *
1913  */
1914 
1915 static void
free_array(char ** argv,size_t entries)1916 free_array(char **argv, size_t entries) {
1917 	char **p = argv;
1918 	int useEntries = (entries > 0U);
1919 
1920 	if (argv == NULL)
1921 		return;
1922 
1923 	while ((useEntries && entries > 0U) || *p) {
1924 		if (*p)
1925 			free(*p);
1926 		p++;
1927 		if (useEntries)
1928 			entries--;
1929 	}
1930 	free(argv);
1931 }
1932 
1933 
1934 
1935 
1936 
1937 /* ************************************************** */
1938 
1939 #if WANT_MAIN
1940 
1941 /*% takes an option to indicate what sort of marshalling(read the code) and
1942    an argument. If the argument looks like a marshalled buffer(has a ':'
1943    embedded) then it's unmarshalled and the remarshalled and the new string
1944    is compared to the old one.
1945 */
1946 
1947 int
main(int argc,char ** argv)1948 main(int argc, char **argv) {
1949 	char buffer[1024];
1950 	char *b = &buffer[0];
1951 	size_t len = sizeof buffer;
1952 	char option;
1953 
1954 	if (argc < 2 || argv[1][0] != '-')
1955 		exit(1);
1956 
1957 	option = argv[1][1];
1958 	argv++;
1959 	argc--;
1960 
1961 
1962 #if 0
1963 	{
1964 		char buff[10];
1965 		char *p = argv[1], *q = &buff[0];
1966 
1967 		while (getfield(&q, sizeof buff, &p, ':') != NULL) {
1968 			printf("field: \"%s\"\n", q);
1969 			p++;
1970 		}
1971 		printf("p is now \"%s\"\n", p);
1972 	}
1973 #endif
1974 
1975 #if 0
1976 	{
1977 		char **x = splitarray(argv[1], argv[1] + strlen(argv[1]),
1978 				      argv[2][0]);
1979 		char **p;
1980 
1981 		if (x == NULL)
1982 			printf("split failed\n");
1983 
1984 		for (p = x ; p != NULL && *p != NULL ; p++) {
1985 			printf("\"%s\"\n", *p);
1986 		}
1987 	}
1988 #endif
1989 
1990 #if 1
1991 	switch(option) {
1992 	case 'n': {
1993 		struct nwent ne;
1994 		int i;
1995 
1996 		if (strchr(argv[1], ':') != NULL) {
1997 			if (irp_unmarshall_nw(&ne, argv[1]) != 0) {
1998 				printf("Unmarhsalling failed\n");
1999 				exit(1);
2000 			}
2001 
2002 			printf("Name: \"%s\"\n", ne.n_name);
2003 			printf("Aliases:");
2004 			for (i = 0 ; ne.n_aliases[i] != NULL ; i++)
2005 				printf("\n\t\"%s\"", ne.n_aliases[i]);
2006 			printf("\nAddrtype: %s\n", ADDR_T_STR(ne.n_addrtype));
2007 			inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length,
2008 				      buffer, sizeof buffer);
2009 			printf("Net: \"%s\"\n", buffer);
2010 			*((long*)ne.n_addr) = htonl(*((long*)ne.n_addr));
2011 			inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length,
2012 				      buffer, sizeof buffer);
2013 			printf("Corrected Net: \"%s\"\n", buffer);
2014 		} else {
2015 			struct netent *np1 = getnetbyname(argv[1]);
2016 			ne.n_name = np1->n_name;
2017 			ne.n_aliases = np1->n_aliases;
2018 			ne.n_addrtype = np1->n_addrtype;
2019 			ne.n_addr = &np1->n_net;
2020 			ne.n_length = (IN_CLASSA(np1->n_net) ?
2021 				       8 :
2022 				       (IN_CLASSB(np1->n_net) ?
2023 					16 :
2024 					(IN_CLASSC(np1->n_net) ?
2025 					 24 : -1)));
2026 			np1->n_net = htonl(np1->n_net);
2027 			if (irp_marshall_nw(&ne, &b, &len) != 0) {
2028 				printf("Marshalling failed\n");
2029 			}
2030 			printf("%s\n", b);
2031 		}
2032 		break;
2033 	}
2034 
2035 
2036 	case 'r': {
2037 		char **hosts, **users, **domains;
2038 		size_t entries;
2039 		int i;
2040 		char *buff;
2041 		size_t size;
2042 		char *ngname;
2043 
2044 		if (strchr(argv[1], '(') != NULL) {
2045 			if (irp_unmarshall_ng(&ngname, &entries,
2046 					      &hosts, &users, &domains,
2047 					      argv[1]) != 0) {
2048 				printf("unmarshall failed\n");
2049 				exit(1);
2050 			}
2051 
2052 #define STRVAL(x) (x == NULL ? "*" : x)
2053 
2054 			printf("%s {\n", ngname);
2055 			for (i = 0 ; i < entries ; i++)
2056 				printf("\t\"%s\" : \"%s\" : \"%s\"\n",
2057 				       STRVAL(hosts[i]),
2058 				       STRVAL(users[i]),
2059 				       STRVAL(domains[i]));
2060 			printf("}\n\n\n");
2061 
2062 
2063 			irp_marshall_ng_start(ngname, NULL, &size);
2064 			for (i = 0 ; i < entries ; i++)
2065 				irp_marshall_ng_next(hosts[i], users[i],
2066 						     domains[i], NULL, &size);
2067 			irp_marshall_ng_end(NULL, &size);
2068 
2069 			buff = malloc(size);
2070 
2071 			irp_marshall_ng_start(ngname, buff, &size);
2072 			for (i = 0 ; i < entries ; i++) {
2073 				if (irp_marshall_ng_next(hosts[i], users[i],
2074 							 domains[i], buff,
2075 							 &size) != 0)
2076 					printf("next marshalling failed.\n");
2077 			}
2078 			irp_marshall_ng_end(buff, &size);
2079 
2080 			if (strcmp_nws(argv[1], buff) != 0) {
2081 				printf("compare failed:\n\t%s\n\t%s\n",
2082 				       buffer, argv[1]);
2083 			} else {
2084 				printf("compare ok\n");
2085 			}
2086 		} else {
2087 			char *h, *u, *d, *buff;
2088 			size_t size;
2089 
2090 			/* run through two times. First to figure out how
2091 			   much of a buffer we need. Second to do the
2092 			   actual marshalling */
2093 
2094 			setnetgrent(argv[1]);
2095 			irp_marshall_ng_start(argv[1], NULL, &size);
2096 			while (getnetgrent(&h, &u, &d) == 1)
2097 				irp_marshall_ng_next(h, u, d, NULL, &size);
2098 			irp_marshall_ng_end(NULL, &size);
2099 			endnetgrent(argv[1]);
2100 
2101 			buff = malloc(size);
2102 
2103 			setnetgrent(argv[1]);
2104 			if (irp_marshall_ng_start(argv[1], buff, &size) != 0)
2105 				printf("Marshalling start failed\n");
2106 
2107 			while (getnetgrent(&h, &u, &d) == 1) {
2108 				if (irp_marshall_ng_next(h, u, d, buff, &size)
2109 				    != 0) {
2110 					printf("Marshalling failed\n");
2111 				}
2112 			}
2113 
2114 			irp_marshall_ng_end(buff, &size);
2115 			endnetgrent();
2116 
2117 			printf("success: %s\n", buff);
2118 		}
2119 		break;
2120 	}
2121 
2122 
2123 
2124 	case 'h': {
2125 		struct hostent he, *hp;
2126 		int i;
2127 
2128 
2129 		if (strchr(argv[1], '@') != NULL) {
2130 			if (irp_unmarshall_ho(&he, argv[1]) != 0) {
2131 				printf("unmarshall failed\n");
2132 				exit(1);
2133 			}
2134 
2135 			printf("Host: \"%s\"\nAliases:", he.h_name);
2136 			for (i = 0 ; he.h_aliases[i] != NULL ; i++)
2137 				printf("\n\t\t\"%s\"", he.h_aliases[i]);
2138 			printf("\nAddr Type: \"%s\"\n",
2139 			       ADDR_T_STR(he.h_addrtype));
2140 			printf("Length: %d\nAddresses:", he.h_length);
2141 			for (i = 0 ; he.h_addr_list[i] != 0 ; i++) {
2142 				inet_ntop(he.h_addrtype, he.h_addr_list[i],
2143 					  buffer, sizeof buffer);
2144 				printf("\n\t\"%s\"\n", buffer);
2145 			}
2146 			printf("\n\n");
2147 
2148 			irp_marshall_ho(&he, &b, &len);
2149 			if (strcmp(argv[1], buffer) != 0) {
2150 				printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
2151 				       buffer, argv[1]);
2152 			} else {
2153 				printf("compare ok\n");
2154 			}
2155 		} else {
2156 			if ((hp = gethostbyname(argv[1])) == NULL) {
2157 				perror("gethostbyname");
2158 				printf("\"%s\"\n", argv[1]);
2159 				exit(1);
2160 			}
2161 
2162 			if (irp_marshall_ho(hp, &b, &len) != 0) {
2163 				printf("irp_marshall_ho failed\n");
2164 				exit(1);
2165 			}
2166 
2167 			printf("success: \"%s\"\n", buffer);
2168 		}
2169 		break;
2170 	}
2171 
2172 
2173 	case 's': {
2174 		struct servent *sv;
2175 		struct servent sv1;
2176 
2177 		if (strchr(argv[1], ':') != NULL) {
2178 			sv = &sv1;
2179 			memset(sv, 0xef, sizeof (struct servent));
2180 			if (irp_unmarshall_sv(sv, argv[1]) != 0) {
2181 				printf("unmarshall failed\n");
2182 
2183 			}
2184 
2185 			irp_marshall_sv(sv, &b, &len);
2186 			if (strcmp(argv[1], buffer) != 0) {
2187 				printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
2188 				       buffer, argv[1]);
2189 			} else {
2190 				printf("compare ok\n");
2191 			}
2192 		} else {
2193 			if ((sv = getservbyname(argv[1], argv[2])) == NULL) {
2194 				perror("getservent");
2195 				exit(1);
2196 			}
2197 
2198 			if (irp_marshall_sv(sv, &b, &len) != 0) {
2199 				printf("irp_marshall_sv failed\n");
2200 				exit(1);
2201 			}
2202 
2203 			printf("success: \"%s\"\n", buffer);
2204 		}
2205 		break;
2206 	}
2207 
2208 	case 'g': {
2209 		struct group *gr;
2210 		struct group gr1;
2211 
2212 		if (strchr(argv[1], ':') != NULL) {
2213 			gr = &gr1;
2214 			memset(gr, 0xef, sizeof (struct group));
2215 			if (irp_unmarshall_gr(gr, argv[1]) != 0) {
2216 				printf("unmarshall failed\n");
2217 
2218 			}
2219 
2220 			irp_marshall_gr(gr, &b, &len);
2221 			if (strcmp(argv[1], buffer) != 0) {
2222 				printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
2223 				       buffer, argv[1]);
2224 			} else {
2225 				printf("compare ok\n");
2226 			}
2227 		} else {
2228 			if ((gr = getgrnam(argv[1])) == NULL) {
2229 				perror("getgrnam");
2230 				exit(1);
2231 			}
2232 
2233 			if (irp_marshall_gr(gr, &b, &len) != 0) {
2234 				printf("irp_marshall_gr failed\n");
2235 				exit(1);
2236 			}
2237 
2238 			printf("success: \"%s\"\n", buffer);
2239 		}
2240 		break;
2241 	}
2242 
2243 
2244 	case 'p': {
2245 		struct passwd *pw;
2246 		struct passwd pw1;
2247 
2248 		if (strchr(argv[1], ':') != NULL) {
2249 			pw = &pw1;
2250 			memset(pw, 0xef, sizeof (*pw));
2251 			if (irp_unmarshall_pw(pw, argv[1]) != 0) {
2252 				printf("unmarshall failed\n");
2253 				exit(1);
2254 			}
2255 
2256 			printf("User: \"%s\"\nPasswd: \"%s\"\nUid: %ld\nGid: %ld\n",
2257 			       pw->pw_name, pw->pw_passwd, (long)pw->pw_uid,
2258 			       (long)pw->pw_gid);
2259 			printf("Class: \"%s\"\nChange: %ld\nGecos: \"%s\"\n",
2260 			       pw->pw_class, (long)pw->pw_change, pw->pw_gecos);
2261 			printf("Shell: \"%s\"\nDirectory: \"%s\"\n",
2262 			       pw->pw_shell, pw->pw_dir);
2263 
2264 			pw = getpwnam(pw->pw_name);
2265 			irp_marshall_pw(pw, &b, &len);
2266 			if (strcmp(argv[1], buffer) != 0) {
2267 				printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
2268 				       buffer, argv[1]);
2269 			} else {
2270 				printf("compare ok\n");
2271 			}
2272 		} else {
2273 			if ((pw = getpwnam(argv[1])) == NULL) {
2274 				perror("getpwnam");
2275 				exit(1);
2276 			}
2277 
2278 			if (irp_marshall_pw(pw, &b, &len) != 0) {
2279 				printf("irp_marshall_pw failed\n");
2280 				exit(1);
2281 			}
2282 
2283 			printf("success: \"%s\"\n", buffer);
2284 		}
2285 		break;
2286 	}
2287 
2288 	default:
2289 		printf("Wrong option: %c\n", option);
2290 		break;
2291 	}
2292 
2293 #endif
2294 
2295 	return (0);
2296 }
2297 
2298 #endif
2299 
2300 /*! \file */
2301