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