xref: /freebsd/sys/netinet/libalias/alias_nbt.c (revision 3642298923e528d795e3a30ec165d2b469e28b40)
1 /*-
2  * Written by Atsushi Murai <amurai@spec.co.jp>
3  * Copyright (c) 1998, System Planning and Engineering Co.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *  TODO:
27  *       oClean up.
28  *       oConsidering for word alignment for other platform.
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 /*
35     alias_nbt.c performs special processing for NetBios over TCP/IP
36     sessions by UDP.
37 
38     Initial version:  May, 1998  (Atsushi Murai <amurai@spec.co.jp>)
39 
40     See HISTORY file for record of revisions.
41 */
42 
43 /* Includes */
44 #ifdef _KERNEL
45 #include <sys/param.h>
46 #include <sys/ctype.h>
47 #include <sys/libkern.h>
48 #else
49 #include <sys/types.h>
50 #include <ctype.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <arpa/inet.h>
54 #endif
55 
56 #include <netinet/in_systm.h>
57 #include <netinet/in.h>
58 #include <netinet/ip.h>
59 #include <netinet/udp.h>
60 #include <netinet/tcp.h>
61 
62 #ifdef _KERNEL
63 #include <netinet/libalias/alias.h>
64 #include <netinet/libalias/alias_local.h>
65 #else
66 #include "alias_local.h"
67 #endif
68 
69 typedef struct {
70 	struct in_addr	oldaddr;
71 	u_short		oldport;
72 	struct in_addr	newaddr;
73 	u_short		newport;
74 	u_short        *uh_sum;
75 }		NBTArguments;
76 
77 typedef struct {
78 	unsigned char	type;
79 	unsigned char	flags;
80 	u_short		id;
81 	struct in_addr	source_ip;
82 	u_short		source_port;
83 	u_short		len;
84 	u_short		offset;
85 }		NbtDataHeader;
86 
87 #define OpQuery		0
88 #define OpUnknown	4
89 #define OpRegist	5
90 #define OpRelease	6
91 #define OpWACK		7
92 #define OpRefresh	8
93 typedef struct {
94 	u_short		nametrid;
95 	u_short		dir:	1, opcode:4, nmflags:7, rcode:4;
96 	u_short		qdcount;
97 	u_short		ancount;
98 	u_short		nscount;
99 	u_short		arcount;
100 }		NbtNSHeader;
101 
102 #define FMT_ERR		0x1
103 #define SRV_ERR		0x2
104 #define IMP_ERR		0x4
105 #define RFS_ERR		0x5
106 #define ACT_ERR		0x6
107 #define CFT_ERR		0x7
108 
109 
110 #ifdef LIBALIAS_DEBUG
111 static void
112 PrintRcode(u_char rcode)
113 {
114 
115 	switch (rcode) {
116 		case FMT_ERR:
117 		printf("\nFormat Error.");
118 	case SRV_ERR:
119 		printf("\nSever failure.");
120 	case IMP_ERR:
121 		printf("\nUnsupported request error.\n");
122 	case RFS_ERR:
123 		printf("\nRefused error.\n");
124 	case ACT_ERR:
125 		printf("\nActive error.\n");
126 	case CFT_ERR:
127 		printf("\nName in conflict error.\n");
128 	default:
129 		printf("\n?%c?=%0x\n", '?', rcode);
130 
131 	}
132 }
133 
134 #endif
135 
136 
137 /* Handling Name field */
138 static u_char  *
139 AliasHandleName(u_char * p, char *pmax)
140 {
141 
142 	u_char *s;
143 	u_char c;
144 	int compress;
145 
146 	/* Following length field */
147 
148 	if (p == NULL || (char *)p >= pmax)
149 		return (NULL);
150 
151 	if (*p & 0xc0) {
152 		p = p + 2;
153 		if ((char *)p > pmax)
154 			return (NULL);
155 		return ((u_char *) p);
156 	}
157 	while ((*p & 0x3f) != 0x00) {
158 		s = p + 1;
159 		if (*p == 0x20)
160 			compress = 1;
161 		else
162 			compress = 0;
163 
164 		/* Get next length field */
165 		p = (u_char *) (p + (*p & 0x3f) + 1);
166 		if ((char *)p > pmax) {
167 			p = NULL;
168 			break;
169 		}
170 #ifdef LIBALIAS_DEBUG
171 		printf(":");
172 #endif
173 		while (s < p) {
174 			if (compress == 1) {
175 				c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
176 #ifdef LIBALIAS_DEBUG
177 				if (isprint(c))
178 					printf("%c", c);
179 				else
180 					printf("<0x%02x>", c);
181 #endif
182 				s += 2;
183 			} else {
184 #ifdef LIBALIAS_DEBUG
185 				printf("%c", *s);
186 #endif
187 				s++;
188 			}
189 		}
190 #ifdef LIBALIAS_DEBUG
191 		printf(":");
192 		fflush(stdout);
193 #endif
194 	}
195 
196 	/* Set up to out of Name field */
197 	if (p == NULL || (char *)p >= pmax)
198 		p = NULL;
199 	else
200 		p++;
201 	return ((u_char *) p);
202 }
203 
204 /*
205  * NetBios Datagram Handler (IP/UDP)
206  */
207 #define DGM_DIRECT_UNIQ		0x10
208 #define DGM_DIRECT_GROUP	0x11
209 #define DGM_BROADCAST		0x12
210 #define DGM_ERROR			0x13
211 #define DGM_QUERY			0x14
212 #define DGM_POSITIVE_RES	0x15
213 #define DGM_NEGATIVE_RES	0x16
214 
215 int
216 AliasHandleUdpNbt(
217     struct libalias *la,
218     struct ip *pip,		/* IP packet to examine/patch */
219     struct alias_link *lnk,
220     struct in_addr *alias_address,
221     u_short alias_port
222 )
223 {
224 	struct udphdr *uh;
225 	NbtDataHeader *ndh;
226 	u_char *p = NULL;
227 	char *pmax;
228 
229 	(void)la;
230 	(void)lnk;
231 
232 	/* Calculate data length of UDP packet */
233 	uh = (struct udphdr *)ip_next(pip);
234 	pmax = (char *)uh + ntohs(uh->uh_ulen);
235 
236 	ndh = (NbtDataHeader *)udp_next(uh);
237 	if ((char *)(ndh + 1) > pmax)
238 		return (-1);
239 #ifdef LIBALIAS_DEBUG
240 	printf("\nType=%02x,", ndh->type);
241 #endif
242 	switch (ndh->type) {
243 	case DGM_DIRECT_UNIQ:
244 	case DGM_DIRECT_GROUP:
245 	case DGM_BROADCAST:
246 		p = (u_char *) ndh + 14;
247 		p = AliasHandleName(p, pmax);	/* Source Name */
248 		p = AliasHandleName(p, pmax);	/* Destination Name */
249 		break;
250 	case DGM_ERROR:
251 		p = (u_char *) ndh + 11;
252 		break;
253 	case DGM_QUERY:
254 	case DGM_POSITIVE_RES:
255 	case DGM_NEGATIVE_RES:
256 		p = (u_char *) ndh + 10;
257 		p = AliasHandleName(p, pmax);	/* Destination Name */
258 		break;
259 	}
260 	if (p == NULL || (char *)p > pmax)
261 		p = NULL;
262 #ifdef LIBALIAS_DEBUG
263 	printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
264 #endif
265 	/* Doing an IP address and Port number Translation */
266 	if (uh->uh_sum != 0) {
267 		int acc;
268 		u_short *sptr;
269 
270 		acc = ndh->source_port;
271 		acc -= alias_port;
272 		sptr = (u_short *) & (ndh->source_ip);
273 		acc += *sptr++;
274 		acc += *sptr;
275 		sptr = (u_short *) alias_address;
276 		acc -= *sptr++;
277 		acc -= *sptr;
278 		ADJUST_CHECKSUM(acc, uh->uh_sum);
279 	}
280 	ndh->source_ip = *alias_address;
281 	ndh->source_port = alias_port;
282 #ifdef LIBALIAS_DEBUG
283 	printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
284 	fflush(stdout);
285 #endif
286 	return ((p == NULL) ? -1 : 0);
287 }
288 
289 /* Question Section */
290 #define QS_TYPE_NB		0x0020
291 #define QS_TYPE_NBSTAT	0x0021
292 #define QS_CLAS_IN		0x0001
293 typedef struct {
294 	u_short		type;	/* The type of Request */
295 	u_short		class;	/* The class of Request */
296 }		NBTNsQuestion;
297 
298 static u_char  *
299 AliasHandleQuestion(
300     u_short count,
301     NBTNsQuestion * q,
302     char *pmax,
303     NBTArguments * nbtarg)
304 {
305 
306 	(void)nbtarg;
307 
308 	while (count != 0) {
309 		/* Name Filed */
310 		q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
311 
312 		if (q == NULL || (char *)(q + 1) > pmax) {
313 			q = NULL;
314 			break;
315 		}
316 		/* Type and Class filed */
317 		switch (ntohs(q->type)) {
318 		case QS_TYPE_NB:
319 		case QS_TYPE_NBSTAT:
320 			q = q + 1;
321 			break;
322 		default:
323 #ifdef LIBALIAS_DEBUG
324 			printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
325 #endif
326 			break;
327 		}
328 		count--;
329 	}
330 
331 	/* Set up to out of Question Section */
332 	return ((u_char *) q);
333 }
334 
335 /* Resource Record */
336 #define RR_TYPE_A		0x0001
337 #define RR_TYPE_NS		0x0002
338 #define RR_TYPE_NULL	0x000a
339 #define RR_TYPE_NB		0x0020
340 #define RR_TYPE_NBSTAT	0x0021
341 #define RR_CLAS_IN		0x0001
342 #define SizeOfNsResource	8
343 typedef struct {
344 	u_short		type;
345 	u_short		class;
346 	unsigned int	ttl;
347 	u_short		rdlen;
348 }		NBTNsResource;
349 
350 #define SizeOfNsRNB			6
351 typedef struct {
352 	u_short		g:	1  , ont:2, resv:13;
353 	struct in_addr	addr;
354 }		NBTNsRNB;
355 
356 static u_char  *
357 AliasHandleResourceNB(
358     NBTNsResource * q,
359     char *pmax,
360     NBTArguments * nbtarg)
361 {
362 	NBTNsRNB *nb;
363 	u_short bcount;
364 
365 	if (q == NULL || (char *)(q + 1) > pmax)
366 		return (NULL);
367 	/* Check out a length */
368 	bcount = ntohs(q->rdlen);
369 
370 	/* Forward to Resource NB position */
371 	nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
372 
373 	/* Processing all in_addr array */
374 #ifdef LIBALIAS_DEBUG
375 	printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
376 	printf("->%s, %dbytes] ", inet_ntoa(nbtarg->newaddr), bcount);
377 #endif
378 	while (nb != NULL && bcount != 0) {
379 		if ((char *)(nb + 1) > pmax) {
380 			nb = NULL;
381 			break;
382 		}
383 #ifdef LIBALIAS_DEBUG
384 		printf("<%s>", inet_ntoa(nb->addr));
385 #endif
386 		if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
387 			if (*nbtarg->uh_sum != 0) {
388 				int acc;
389 				u_short *sptr;
390 
391 				sptr = (u_short *) & (nb->addr);
392 				acc = *sptr++;
393 				acc += *sptr;
394 				sptr = (u_short *) & (nbtarg->newaddr);
395 				acc -= *sptr++;
396 				acc -= *sptr;
397 				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
398 			}
399 			nb->addr = nbtarg->newaddr;
400 #ifdef LIBALIAS_DEBUG
401 			printf("O");
402 #endif
403 		}
404 #ifdef LIBALIAS_DEBUG
405 		else {
406 			printf(".");
407 		}
408 #endif
409 		nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
410 		bcount -= SizeOfNsRNB;
411 	}
412 	if (nb == NULL || (char *)(nb + 1) > pmax) {
413 		nb = NULL;
414 	}
415 	return ((u_char *) nb);
416 }
417 
418 #define SizeOfResourceA		6
419 typedef struct {
420 	struct in_addr	addr;
421 }		NBTNsResourceA;
422 
423 static u_char  *
424 AliasHandleResourceA(
425     NBTNsResource * q,
426     char *pmax,
427     NBTArguments * nbtarg)
428 {
429 	NBTNsResourceA *a;
430 	u_short bcount;
431 
432 	if (q == NULL || (char *)(q + 1) > pmax)
433 		return (NULL);
434 
435 	/* Forward to Resource A position */
436 	a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
437 
438 	/* Check out of length */
439 	bcount = ntohs(q->rdlen);
440 
441 	/* Processing all in_addr array */
442 #ifdef LIBALIAS_DEBUG
443 	printf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
444 	printf("->%s]", inet_ntoa(nbtarg->newaddr));
445 #endif
446 	while (bcount != 0) {
447 		if (a == NULL || (char *)(a + 1) > pmax)
448 			return (NULL);
449 #ifdef LIBALIAS_DEBUG
450 		printf("..%s", inet_ntoa(a->addr));
451 #endif
452 		if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
453 			if (*nbtarg->uh_sum != 0) {
454 				int acc;
455 				u_short *sptr;
456 
457 				sptr = (u_short *) & (a->addr);	/* Old */
458 				acc = *sptr++;
459 				acc += *sptr;
460 				sptr = (u_short *) & nbtarg->newaddr;	/* New */
461 				acc -= *sptr++;
462 				acc -= *sptr;
463 				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
464 			}
465 			a->addr = nbtarg->newaddr;
466 		}
467 		a++;		/* XXXX */
468 		bcount -= SizeOfResourceA;
469 	}
470 	if (a == NULL || (char *)(a + 1) > pmax)
471 		a = NULL;
472 	return ((u_char *) a);
473 }
474 
475 typedef struct {
476 	u_short		opcode:4, flags:8, resv:4;
477 }		NBTNsResourceNULL;
478 
479 static u_char  *
480 AliasHandleResourceNULL(
481     NBTNsResource * q,
482     char *pmax,
483     NBTArguments * nbtarg)
484 {
485 	NBTNsResourceNULL *n;
486 	u_short bcount;
487 
488 	(void)nbtarg;
489 
490 	if (q == NULL || (char *)(q + 1) > pmax)
491 		return (NULL);
492 
493 	/* Forward to Resource NULL position */
494 	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
495 
496 	/* Check out of length */
497 	bcount = ntohs(q->rdlen);
498 
499 	/* Processing all in_addr array */
500 	while (bcount != 0) {
501 		if ((char *)(n + 1) > pmax) {
502 			n = NULL;
503 			break;
504 		}
505 		n++;
506 		bcount -= sizeof(NBTNsResourceNULL);
507 	}
508 	if ((char *)(n + 1) > pmax)
509 		n = NULL;
510 
511 	return ((u_char *) n);
512 }
513 
514 static u_char  *
515 AliasHandleResourceNS(
516     NBTNsResource * q,
517     char *pmax,
518     NBTArguments * nbtarg)
519 {
520 	NBTNsResourceNULL *n;
521 	u_short bcount;
522 
523 	(void)nbtarg;
524 
525 	if (q == NULL || (char *)(q + 1) > pmax)
526 		return (NULL);
527 
528 	/* Forward to Resource NULL position */
529 	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
530 
531 	/* Check out of length */
532 	bcount = ntohs(q->rdlen);
533 
534 	/* Resource Record Name Filed */
535 	q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax);	/* XXX */
536 
537 	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
538 		return (NULL);
539 	else
540 		return ((u_char *) n + bcount);
541 }
542 
543 typedef struct {
544 	u_short		numnames;
545 }		NBTNsResourceNBSTAT;
546 
547 static u_char  *
548 AliasHandleResourceNBSTAT(
549     NBTNsResource * q,
550     char *pmax,
551     NBTArguments * nbtarg)
552 {
553 	NBTNsResourceNBSTAT *n;
554 	u_short bcount;
555 
556 	(void)nbtarg;
557 
558 	if (q == NULL || (char *)(q + 1) > pmax)
559 		return (NULL);
560 
561 	/* Forward to Resource NBSTAT position */
562 	n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
563 
564 	/* Check out of length */
565 	bcount = ntohs(q->rdlen);
566 
567 	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
568 		return (NULL);
569 	else
570 		return ((u_char *) n + bcount);
571 }
572 
573 static u_char  *
574 AliasHandleResource(
575     u_short count,
576     NBTNsResource * q,
577     char *pmax,
578     NBTArguments
579     * nbtarg)
580 {
581 	while (count != 0) {
582 		/* Resource Record Name Filed */
583 		q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
584 
585 		if (q == NULL || (char *)(q + 1) > pmax)
586 			break;
587 #ifdef LIBALIAS_DEBUG
588 		printf("type=%02x, count=%d\n", ntohs(q->type), count);
589 #endif
590 
591 		/* Type and Class filed */
592 		switch (ntohs(q->type)) {
593 		case RR_TYPE_NB:
594 			q = (NBTNsResource *) AliasHandleResourceNB(
595 			    q,
596 			    pmax,
597 			    nbtarg
598 			    );
599 			break;
600 		case RR_TYPE_A:
601 			q = (NBTNsResource *) AliasHandleResourceA(
602 			    q,
603 			    pmax,
604 			    nbtarg
605 			    );
606 			break;
607 		case RR_TYPE_NS:
608 			q = (NBTNsResource *) AliasHandleResourceNS(
609 			    q,
610 			    pmax,
611 			    nbtarg
612 			    );
613 			break;
614 		case RR_TYPE_NULL:
615 			q = (NBTNsResource *) AliasHandleResourceNULL(
616 			    q,
617 			    pmax,
618 			    nbtarg
619 			    );
620 			break;
621 		case RR_TYPE_NBSTAT:
622 			q = (NBTNsResource *) AliasHandleResourceNBSTAT(
623 			    q,
624 			    pmax,
625 			    nbtarg
626 			    );
627 			break;
628 		default:
629 #ifdef LIBALIAS_DEBUG
630 			printf(
631 			    "\nUnknown Type of Resource %0x\n",
632 			    ntohs(q->type)
633 			    );
634 			fflush(stdout);
635 #endif
636 			break;
637 		}
638 		count--;
639 	}
640 	return ((u_char *) q);
641 }
642 
643 int
644 AliasHandleUdpNbtNS(
645     struct libalias *la,
646     struct ip *pip,		/* IP packet to examine/patch */
647     struct alias_link *lnk,
648     struct in_addr *alias_address,
649     u_short * alias_port,
650     struct in_addr *original_address,
651     u_short * original_port)
652 {
653 	struct udphdr *uh;
654 	NbtNSHeader *nsh;
655 	u_char *p;
656 	char *pmax;
657 	NBTArguments nbtarg;
658 
659 	(void)la;
660 	(void)lnk;
661 
662 	/* Set up Common Parameter */
663 	nbtarg.oldaddr = *alias_address;
664 	nbtarg.oldport = *alias_port;
665 	nbtarg.newaddr = *original_address;
666 	nbtarg.newport = *original_port;
667 
668 	/* Calculate data length of UDP packet */
669 	uh = (struct udphdr *)ip_next(pip);
670 	nbtarg.uh_sum = &(uh->uh_sum);
671 	nsh = (NbtNSHeader *)udp_next(uh);
672 	p = (u_char *) (nsh + 1);
673 	pmax = (char *)uh + ntohs(uh->uh_ulen);
674 
675 	if ((char *)(nsh + 1) > pmax)
676 		return (-1);
677 
678 #ifdef LIBALIAS_DEBUG
679 	printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
680 	    ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
681 	    nsh->dir ? "Response" : "Request",
682 	    nsh->nametrid,
683 	    nsh->opcode,
684 	    nsh->nmflags,
685 	    nsh->rcode,
686 	    ntohs(nsh->qdcount),
687 	    ntohs(nsh->ancount),
688 	    ntohs(nsh->nscount),
689 	    ntohs(nsh->arcount),
690 	    (u_char *) p - (u_char *) nsh
691 	    );
692 #endif
693 
694 	/* Question Entries */
695 	if (ntohs(nsh->qdcount) != 0) {
696 		p = AliasHandleQuestion(
697 		    ntohs(nsh->qdcount),
698 		    (NBTNsQuestion *) p,
699 		    pmax,
700 		    &nbtarg
701 		    );
702 	}
703 	/* Answer Resource Records */
704 	if (ntohs(nsh->ancount) != 0) {
705 		p = AliasHandleResource(
706 		    ntohs(nsh->ancount),
707 		    (NBTNsResource *) p,
708 		    pmax,
709 		    &nbtarg
710 		    );
711 	}
712 	/* Authority Resource Recodrs */
713 	if (ntohs(nsh->nscount) != 0) {
714 		p = AliasHandleResource(
715 		    ntohs(nsh->nscount),
716 		    (NBTNsResource *) p,
717 		    pmax,
718 		    &nbtarg
719 		    );
720 	}
721 	/* Additional Resource Recodrs */
722 	if (ntohs(nsh->arcount) != 0) {
723 		p = AliasHandleResource(
724 		    ntohs(nsh->arcount),
725 		    (NBTNsResource *) p,
726 		    pmax,
727 		    &nbtarg
728 		    );
729 	}
730 #ifdef LIBALIAS_DEBUG
731 	PrintRcode(nsh->rcode);
732 #endif
733 	return ((p == NULL) ? -1 : 0);
734 }
735