1/*
2 * Copyright (c) 2000, Boris Popov
3 * All rights reserved.
4 *
5 * Portions Copyright (C) 2005 - 2010 Apple Inc. All rights reserved
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *    This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35#include <sys/param.h>
36#include <sys/errno.h>
37#include <sys/stat.h>
38#include <sys/socket.h>
39#include <err.h>
40#include <stdio.h>
41#include <unistd.h>
42#include <strings.h>
43#include <stdlib.h>
44#include <sysexits.h>
45
46#include <SMBClient/smbclient.h>
47#include <SMBClient/netbios.h>
48#include <arpa/inet.h>
49
50#include "common.h"
51
52/*
53 * Make a copy of the name and if request unpercent escape the name
54 */
55static char *
56getHostName(const char *name, Boolean escapeNames)
57{
58	char *newName = strdup(name);
59	CFStringRef nameRef = NULL;
60	CFStringRef newNameRef = NULL;
61
62	/* They don't want it escape or the strdup failed */
63	if (!escapeNames || !newName) {
64		return newName;
65	}
66	/* Get a CFString */
67	nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingUTF8);
68
69	/* unpercent escape out the CFString */
70	if (nameRef) {
71		newNameRef = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
72																			 nameRef, CFSTR(" "), kCFStringEncodingUTF8);
73	}
74	/* Now create an unpercent escape out c style string */
75	if (newNameRef) {
76		int maxlen = (int)CFStringGetLength(newNameRef)+1;
77		char *tempName = malloc(maxlen);
78
79		if (tempName) {
80			free(newName);
81			newName = tempName;
82			CFStringGetCString(newNameRef, newName, maxlen, kCFStringEncodingUTF8);
83		}
84	}
85
86	if (nameRef) {
87		CFRelease(nameRef);
88	}
89	if (newNameRef) {
90		CFRelease(newNameRef);
91	}
92	return newName;
93}
94
95
96int
97cmd_lookup(int argc, char *argv[])
98{
99	char *hostname;
100	int opt;
101	struct sockaddr_storage *startAddr = NULL, *listAddr = NULL;
102	const char *winsServer = NULL;
103	int32_t ii, count = 0;
104	struct sockaddr_storage respAddr;
105	struct sockaddr_in *in4 = NULL;
106	struct sockaddr_in6 *in6 = NULL;
107	char addrStr[INET6_ADDRSTRLEN+1];
108	uint8_t nodeType = kNetBIOSFileServerService;
109	Boolean escapeNames= FALSE;
110
111	bzero(&respAddr, sizeof(respAddr));
112	if (argc < 2)
113		lookup_usage();
114	while ((opt = getopt(argc, argv, "ew:t:")) != EOF) {
115		switch(opt) {
116			case 'e':
117				escapeNames = TRUE;
118				break;
119			case 'w':
120				winsServer = optarg;
121				break;
122			case 't':
123				errno = 0;
124				nodeType = (uint8_t)strtol(optarg, NULL, 0);
125				if (errno)
126					errx(EX_DATAERR, "invalid value for node type");
127				break;
128		    default:
129				lookup_usage();
130				/*NOTREACHED*/
131		}
132	}
133	if (optind >= argc)
134		lookup_usage();
135
136	hostname = getHostName(argv[argc - 1], escapeNames);
137	if (!hostname) {
138		err(EX_OSERR, "failed to resolve %s", argv[argc - 1]);
139	}
140
141	startAddr = listAddr = SMBResolveNetBIOSNameEx(hostname, nodeType, winsServer,
142													0, &respAddr, &count);
143	if (startAddr == NULL) {
144		err(EX_NOHOST, "unable to resolve %s", hostname);
145	}
146
147	if (respAddr.ss_family == AF_INET) {
148		in4 = (struct sockaddr_in *)&respAddr;
149		inet_ntop(respAddr.ss_family, &in4->sin_addr, addrStr, sizeof(addrStr));
150	} else if (respAddr.ss_family == AF_INET6) {
151		in6 = (struct sockaddr_in6 *)&respAddr;
152		inet_ntop(respAddr.ss_family, &in6->sin6_addr, addrStr, sizeof(addrStr));
153	} else {
154		strcpy(addrStr, "unknown address family");
155	}
156
157	fprintf(stdout, "Got response from %s\n", addrStr);
158
159	for (ii=0; ii < count; ii++) {
160		if (listAddr->ss_family == AF_INET) {
161			in4 = (struct sockaddr_in *)listAddr;
162			inet_ntop(listAddr->ss_family, &in4->sin_addr, addrStr, sizeof(addrStr));
163		} else if (respAddr.ss_family == AF_INET6) {
164			in6 = (struct sockaddr_in6 *)listAddr;
165			inet_ntop(respAddr.ss_family, &in6->sin6_addr, addrStr, sizeof(addrStr));
166		} else {
167			strcpy(addrStr, "unknown address family");
168		}
169		fprintf(stdout, "IP address of %s: %s\n", hostname, addrStr);
170		listAddr++;
171	}
172	if (startAddr) {
173		free(startAddr);
174	}
175	if (hostname) {
176		free(hostname);
177	}
178	return 0;
179}
180
181
182void
183lookup_usage(void)
184{
185	fprintf(stderr, "usage: smbutil lookup [-e] [-w host] [-t node type] name\n");
186	exit(1);
187}
188