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