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)
52static 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
57Check values are in approrpriate endian order.
58
59Double 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
94static char    *strndup(const char *str, size_t len);
95#endif
96
97static char   **splitarray(const char *buffer, const char *buffend, char delim);
98static int	joinarray(char * const * argv, char *buffer, char delim);
99static char    *getfield(char **res, size_t reslen, char **buffer, char delim);
100static size_t	joinlength(char * const *argv);
101static 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
108static char COMMA = ',';
109
110static const char *COMMASTR = ",";
111static 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
134int
135irp_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
231int
232irp_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
409int
410irp_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
476int
477irp_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
578int
579irp_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
642int
643irp_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
738int
739irp_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
797int 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
884int
885irp_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
991int
992irp_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
1146int
1147irp_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
1218int
1219irp_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
1313int
1314irp_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
1379int
1380irp_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
1487int
1488irp_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
1553int
1554irp_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
1659static char **
1660splitarray(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
1729static size_t
1730joinlength(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
1757static int
1758joinarray(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
1798static char *
1799getfield(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
1849static char *
1850strndup(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
1874static int
1875strcmp_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
1916static void
1917free_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
1948int
1949main(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