Libinfo-173.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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (C) 1990 by NeXT, Inc. All rights reserved.
27 */
28
29 /*
30 * ni_pwdomain function: present working domain for a netinfo handle
31 *
32 * usage:
33 * ni_status ni_pwdomain(void *ni, ni_name *buf)
34 *
35 * pwd is returned in buf, which can be freed with ni_name_free
36 */
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <netinfo/ni.h>
44 #include <string.h>
45 #include <sys/socket.h>
46 #include <net/if.h>
47 #include <sys/ioctl.h>
48 #include "sys_interfaces.h"
49
50 extern char *inet_ntoa();
51
52 static const char NAME_NAME[] = "name";
53 static const char NAME_MACHINES[] = "machines";
54 static const char NAME_IP_ADDRESS[] = "ip_address";
55 static const char NAME_SERVES[] = "serves";
56 static const char NAME_UNKNOWN[] = "###UNKNOWN###";
57
58 static ni_name
59 escape_domain(ni_name name)
60 {
61 int extra;
62 char *p;
63 char *s;
64 ni_name newname;
65
66 extra = 0;
67 for (p = name; *p; p++)
68 {
69 if ((*p == '/') || (*p == '\\')) extra++;
70 }
71
72 newname = malloc(strlen(name) + extra + 1);
73 s = newname;
74 for (p = name; *p; p++)
75 {
76 if ((*p == '/') || (*p == '\\')) *s++ = '\\';
77 *s++ = *p;
78 }
79
80 *s = 0;
81 return newname;
82
83 }
84
85 static char *
86 finddomain(void *ni, struct in_addr addr, ni_name tag)
87 {
88 ni_id nid;
89 ni_idlist idl;
90 ni_namelist nl;
91 ni_index i;
92 ni_name slash;
93 ni_name domain;
94 ni_status status;
95
96 status = ni_root(ni, &nid);
97 if (status != NI_OK) return NULL;
98
99 status = ni_lookup(ni, &nid, NAME_NAME, NAME_MACHINES, &idl);
100 if (status != NI_OK) return NULL;
101
102 nid.nii_object = idl.niil_val[0];
103 ni_idlist_free(&idl);
104
105 status = ni_lookup(ni, &nid, NAME_IP_ADDRESS, inet_ntoa(addr), &idl);
106 if (status != NI_OK) return NULL;
107
108 nid.nii_object = idl.niil_val[0];
109 ni_idlist_free(&idl);
110
111 status = ni_lookupprop(ni, &nid, NAME_SERVES, &nl);
112 if (status != NI_OK) return NULL;
113
114 for (i = 0; i < nl.ninl_len; i++)
115 {
116 slash = rindex(nl.ninl_val[i], '/');
117 if (slash == NULL) continue;
118
119 if (ni_name_match(slash + 1, tag))
120 {
121 *slash = 0;
122 domain = escape_domain(nl.ninl_val[i]);
123 ni_namelist_free(&nl);
124 return domain;
125 }
126 }
127
128 ni_namelist_free(&nl);
129
130 return NULL;
131 }
132
133 static char *
134 ni_domainof(void *ni, void *parent)
135 {
136 struct sockaddr_in addr;
137 ni_name tag;
138 ni_name dom;
139 ni_status status;
140 interface_list_t *ilist;
141 int i;
142
143 status = ni_addrtag(ni, &addr, &tag);
144 if (status != NI_OK) return ni_name_dup(NAME_UNKNOWN);
145
146 dom = finddomain(parent, addr.sin_addr, tag);
147 if (dom != NULL)
148 {
149 ni_name_free(&tag);
150 return dom;
151 }
152
153 ilist = sys_interfaces();
154 if (ilist == NULL) return ni_name_dup(NAME_UNKNOWN);
155 if (sys_is_my_address(ilist, &(addr.sin_addr)))
156 {
157 /* Try all my non-loopback interfaces */
158 for (i = 0; i < ilist->count; i++)
159 {
160 if (ilist->interface[i].addr.s_addr == htonl(INADDR_LOOPBACK)) continue;
161
162 addr.sin_addr.s_addr = ilist->interface[i].addr.s_addr;
163 dom = finddomain(parent, addr.sin_addr, tag);
164 if (dom != NULL)
165 {
166 ni_name_free(&tag);
167 sys_interfaces_release(ilist);
168 return dom;
169 }
170 }
171 }
172 sys_interfaces_release(ilist);
173
174 dom = malloc(strlen(tag) + 256);
175 sprintf(dom, "%s@%s", tag, inet_ntoa(addr.sin_addr.s_addr));
176 ni_name_free(&tag);
177 return dom;
178 }
179
180 static ni_status
181 _ni_pwdomain(void *ni, ni_name *buf)
182 {
183 void *nip;
184 ni_status status;
185 int len;
186 char *dom;
187
188 /* Open domain name */
189 nip = ni_new(ni, "..");
190 if (nip == NULL)
191 {
192 (*buf) = malloc(2);
193 (*buf)[0] = 0;
194 return NI_OK;
195 }
196
197 /* Get parent's name */
198 status = _ni_pwdomain(nip, buf);
199 if (status != NI_OK) return status;
200
201 /* Get my name relative to my parent */
202 dom = ni_domainof(ni, nip);
203
204 /* Append my relative name to my parent's name */
205 len = strlen(*buf);
206 *buf = realloc(*buf, len + 1 + strlen(dom) + 1);
207 (*buf)[len] = '/';
208 strcpy(&(*buf)[len + 1], dom);
209 ni_name_free(&dom);
210 ni_free(nip);
211
212 return NI_OK;
213 }
214
215 /*
216 * Just call the recursive ni_pwdomain above, and then fix for case of root
217 * domain or error
218 */
219 ni_status
220 ni_pwdomain(void *ni, ni_name *buf)
221 {
222 ni_status status;
223
224 *buf = NULL;
225 status = _ni_pwdomain(ni, buf);
226 if (status != NI_OK)
227 {
228 if (*buf != NULL) ni_name_free(buf);
229 return status;
230 }
231
232 if ((*buf)[0] == 0)
233 {
234 (*buf)[0] = '/';
235 (*buf)[1] = 0;
236 }
237
238 return NI_OK;
239 }