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