Libinfo-78.tar.gz
[apple/libinfo.git] / netinfo.subproj / ni_pwdomain.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Copyright (C) 1990 by NeXT, Inc. All rights reserved.
26 */
27
28 /*
29 * ni_pwdomain function: present working domain for a netinfo handle
30 *
31 * usage:
32 * ni_status ni_pwdomain(void *ni, ni_name *buf)
33 *
34 * pwd is returned in buf, which can be freed with ni_name_free
35 */
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <netinfo/ni.h>
43 #include <string.h>
44 #include <sys/socket.h>
45 #include <net/if.h>
46 #include <sys/ioctl.h>
47
48 extern char *inet_ntoa();
49
50 static const char NAME_NAME[] = "name";
51 static const char NAME_MACHINES[] = "machines";
52 static const char NAME_IP_ADDRESS[] = "ip_address";
53 static const char NAME_SERVES[] = "serves";
54 static const char NAME_UNKNOWN[] = "###UNKNOWN###";
55
56 typedef struct
57 {
58 char name[IFNAMSIZ];
59 short flags;
60 struct in_addr addr;
61 struct in_addr mask;
62 struct in_addr netaddr;
63 struct in_addr bcast;
64 } interface_t;
65
66 typedef struct
67 {
68 unsigned int count;
69 interface_t *interface;
70 } interface_list_t;
71
72 static interface_list_t *my_interfaces = NULL;
73
74 static interface_list_t *
75 sys_interfaces(void)
76 {
77 struct ifconf ifc;
78 struct ifreq *ifr;
79 char buf[1024]; /* XXX */
80 int offset, addrlen, extra, delta;
81 int sock;
82 interface_t *iface;
83
84 if (my_interfaces != NULL) return my_interfaces;
85
86 sock = socket(AF_INET, SOCK_DGRAM, 0);
87
88 if (sock < 0) return NULL;
89
90 ifc.ifc_len = sizeof(buf);
91 ifc.ifc_buf = buf;
92
93 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
94 {
95 close(sock);
96 return NULL;
97 }
98
99 my_interfaces = (interface_list_t *)malloc(sizeof(interface_list_t));
100 my_interfaces->count = 0;
101 my_interfaces->interface = NULL;
102
103 delta = sizeof(struct ifreq);
104 addrlen = delta - IFNAMSIZ;
105 extra = 0;
106
107 offset = 0;
108
109 while (offset <= ifc.ifc_len)
110 {
111 ifr = (struct ifreq *)(ifc.ifc_buf + offset);
112
113 #ifndef _NO_SOCKADDR_LENGTH_
114 extra = ifr->ifr_addr.sa_len - addrlen;
115 if (extra < 0) extra = 0;
116 #endif
117
118 offset = offset + delta + extra;
119
120 if (ifr->ifr_addr.sa_family != AF_INET) continue;
121 if (ioctl(sock, SIOCGIFFLAGS, (char *)ifr) < 0) continue;
122
123 my_interfaces->count++;
124 if (my_interfaces->count == 1)
125 {
126 my_interfaces->interface = (interface_t *)malloc(sizeof(interface_t));
127 }
128 else
129 {
130 my_interfaces->interface = (interface_t *)realloc(my_interfaces->interface, my_interfaces->count * sizeof(interface_t));
131 }
132
133 iface = &(my_interfaces->interface[my_interfaces->count - 1]);
134 memset(iface, 0, sizeof(interface_t));
135
136 memmove(iface->name, ifr->ifr_name, IFNAMSIZ);
137 iface->flags = ifr->ifr_ifru.ifru_flags;
138 iface->addr.s_addr = ((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr.s_addr;
139 ioctl(sock, SIOCGIFNETMASK, (char *)ifr);
140 iface->mask.s_addr = ((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr.s_addr;
141 iface->netaddr.s_addr = iface->addr.s_addr & iface->mask.s_addr;
142 iface->bcast.s_addr = iface->netaddr.s_addr | (~iface->mask.s_addr);
143 }
144
145 close(sock);
146 return my_interfaces;
147 }
148
149 static ni_name
150 escape_domain(ni_name name)
151 {
152 int extra;
153 char *p;
154 char *s;
155 ni_name newname;
156
157 extra = 0;
158 for (p = name; *p; p++)
159 {
160 if ((*p == '/') || (*p == '\\')) extra++;
161 }
162
163 newname = malloc(strlen(name) + extra + 1);
164 s = newname;
165 for (p = name; *p; p++)
166 {
167 if ((*p == '/') || (*p == '\\')) *s++ = '\\';
168 *s++ = *p;
169 }
170
171 *s = 0;
172 return newname;
173
174 }
175
176 static char *
177 finddomain(void *ni, struct in_addr addr, ni_name tag)
178 {
179 ni_id nid;
180 ni_idlist idl;
181 ni_namelist nl;
182 ni_index i;
183 ni_name slash;
184 ni_name domain;
185 ni_status status;
186
187 status = ni_root(ni, &nid);
188 if (status != NI_OK) return NULL;
189
190 status = ni_lookup(ni, &nid, NAME_NAME, NAME_MACHINES, &idl);
191 if (status != NI_OK) return NULL;
192
193 nid.nii_object = idl.niil_val[0];
194 ni_idlist_free(&idl);
195
196 status = ni_lookup(ni, &nid, NAME_IP_ADDRESS, inet_ntoa(addr), &idl);
197 if (status != NI_OK) return NULL;
198
199 nid.nii_object = idl.niil_val[0];
200 ni_idlist_free(&idl);
201
202 status = ni_lookupprop(ni, &nid, NAME_SERVES, &nl);
203 if (status != NI_OK) return NULL;
204
205 for (i = 0; i < nl.ninl_len; i++)
206 {
207 slash = rindex(nl.ninl_val[i], '/');
208 if (slash == NULL) continue;
209
210 if (ni_name_match(slash + 1, tag))
211 {
212 *slash = 0;
213 domain = escape_domain(nl.ninl_val[i]);
214 ni_namelist_free(&nl);
215 return domain;
216 }
217 }
218
219 ni_namelist_free(&nl);
220
221 return NULL;
222 }
223
224 static int
225 sys_is_my_address(struct in_addr *a)
226 {
227 int i;
228 interface_list_t *l;
229
230 l = sys_interfaces();
231 if (l == NULL) return 0;
232
233 for (i = 0; i < l->count; i++)
234 {
235 if (a->s_addr == l->interface[i].addr.s_addr) return 1;
236 }
237 return 0;
238 }
239
240 static char *
241 ni_domainof(void *ni, void *parent)
242 {
243 struct sockaddr_in addr;
244 ni_name tag;
245 ni_name dom;
246 ni_status status;
247 interface_list_t *ilist;
248 int i;
249
250 status = ni_addrtag(ni, &addr, &tag);
251 if (status != NI_OK) return ni_name_dup(NAME_UNKNOWN);
252
253 dom = finddomain(parent, addr.sin_addr, tag);
254 if (dom != NULL)
255 {
256 ni_name_free(&tag);
257 return dom;
258 }
259
260 if (sys_is_my_address(&(addr.sin_addr)))
261 {
262 /* Try all my non-loopback interfaces */
263 ilist = sys_interfaces();
264 if (ilist == NULL) return ni_name_dup(NAME_UNKNOWN);
265
266 for (i = 0; i < ilist->count; i++)
267 {
268 if (ilist->interface[i].addr.s_addr == htonl(INADDR_LOOPBACK)) continue;
269
270 addr.sin_addr.s_addr = ilist->interface[i].addr.s_addr;
271 dom = finddomain(parent, addr.sin_addr, tag);
272 if (dom != NULL)
273 {
274 ni_name_free(&tag);
275 return dom;
276 }
277 }
278 }
279
280 dom = malloc(strlen(tag) + 256);
281 sprintf(dom, "%s@%s", tag, inet_ntoa(addr.sin_addr.s_addr));
282 ni_name_free(&tag);
283 return dom;
284 }
285
286 static ni_status
287 _ni_pwdomain(void *ni, ni_name *buf)
288 {
289 void *nip;
290 ni_status status;
291 int len;
292 char *dom;
293
294 /* Open domain name */
295 nip = ni_new(ni, "..");
296 if (nip == NULL)
297 {
298 (*buf) = malloc(2);
299 (*buf)[0] = 0;
300 return NI_OK;
301 }
302
303 /* Get parent's name */
304 status = _ni_pwdomain(nip, buf);
305 if (status != NI_OK) return status;
306
307 /* Get my name relative to my parent */
308 dom = ni_domainof(ni, nip);
309
310 /* Append my relative name to my parent's name */
311 len = strlen(*buf);
312 *buf = realloc(*buf, len + 1 + strlen(dom) + 1);
313 (*buf)[len] = '/';
314 strcpy(&(*buf)[len + 1], dom);
315 ni_name_free(&dom);
316 ni_free(nip);
317
318 return NI_OK;
319 }
320
321 /*
322 * Just call the recursive ni_pwdomain above, and then fix for case of root
323 * domain or error
324 */
325 ni_status
326 ni_pwdomain(void *ni, ni_name *buf)
327 {
328 ni_status status;
329
330 *buf = NULL;
331 status = _ni_pwdomain(ni, buf);
332 if (status != NI_OK)
333 {
334 if (*buf != NULL) ni_name_free(buf);
335 return status;
336 }
337
338 if ((*buf)[0] == 0)
339 {
340 (*buf)[0] = '/';
341 (*buf)[1] = 0;
342 }
343
344 return NI_OK;
345 }