-adding GNUNET_CONFIGURATION_load_from
[oweals/gnunet.git] / src / util / win.cc
1 /*\r
2      This file is part of GNUnet.\r
3      (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors)\r
4 \r
5      GNUnet is free software; you can redistribute it and/or modify\r
6      it under the terms of the GNU General Public License as published\r
7      by the Free Software Foundation; either version 2, or (at your\r
8      option) any later version.\r
9 \r
10      GNUnet is distributed in the hope that it will be useful, but\r
11      WITHOUT ANY WARRANTY; without even the implied warranty of\r
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
13      General Public License for more details.\r
14 \r
15      You should have received a copy of the GNU General Public License\r
16      along with GNUnet; see the file COPYING.  If not, write to the\r
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
18      Boston, MA 02111-1307, USA.\r
19 */\r
20 \r
21 /**\r
22  * @file util/win.cc\r
23  * @brief Helper functions for MS Windows in C++\r
24  * @author Nils Durner\r
25  */\r
26 \r
27 #ifndef _WIN_CC\r
28 #define _WIN_CC\r
29 \r
30 #include "winproc.h"\r
31 #include "platform.h"\r
32 #include "gnunet_common.h"\r
33 #include "gnunet_connection_lib.h"\r
34 \r
35 #include <list>\r
36 using namespace std;\r
37 #include <ntdef.h>\r
38 \r
39 #ifndef INHERITED_ACE\r
40 #define INHERITED_ACE 0x10\r
41 #endif\r
42 \r
43 extern "C" {\r
44 \r
45 int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows);\r
46 \r
47 #define _IP_ADAPTER_UNICAST_ADDRESS_HEAD \\r
48   union { \\r
49     struct { \\r
50       ULONG Length; \\r
51       DWORD Flags; \\r
52     }; \\r
53   }; \\r
54 \r
55 #define _IP_ADAPTER_UNICAST_ADDRESS_BASE \\r
56   SOCKET_ADDRESS                     Address; \\r
57   IP_PREFIX_ORIGIN                   PrefixOrigin; \\r
58   IP_SUFFIX_ORIGIN                   SuffixOrigin; \\r
59   IP_DAD_STATE                       DadState; \\r
60   ULONG                              ValidLifetime; \\r
61   ULONG                              PreferredLifetime; \\r
62   ULONG                              LeaseLifetime;\r
63 \r
64 #define _IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA \\r
65   UINT8                              OnLinkPrefixLength;\r
66 \r
67 \r
68 #define _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(suffix,addition) \\r
69 typedef struct _IP_ADAPTER_UNICAST_ADDRESS##suffix { \\r
70   _IP_ADAPTER_UNICAST_ADDRESS_HEAD \\r
71   struct _IP_ADAPTER_UNICAST_ADDRESS##suffix *Next; \\r
72   _IP_ADAPTER_UNICAST_ADDRESS_BASE \\r
73   addition \\r
74 } IP_ADAPTER_UNICAST_ADDRESS##suffix, *PIP_ADAPTER_UNICAST_ADDRESS##suffix;\r
75 \r
76 /* _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(,) defined in w32api headers */\r
77 _IP_ADAPTER_UNICAST_ADDRESS_DEFINE(_VISTA,_IP_ADAPTER_UNICAST_ADDRESS_ADD_VISTA)\r
78 \r
79 \r
80 typedef struct _IP_ADAPTER_WINS_SERVER_ADDRESS {\r
81   union {\r
82     ULONGLONG Alignment;\r
83     struct {\r
84       ULONG Length;\r
85       DWORD Reserved;\r
86     };\r
87   };\r
88   struct _IP_ADAPTER_WINS_SERVER_ADDRESS  *Next;\r
89   SOCKET_ADDRESS                         Address;\r
90 } IP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS, *PIP_ADAPTER_WINS_SERVER_ADDRESS_LH;\r
91 \r
92 typedef struct _IP_ADAPTER_GATEWAY_ADDRESS {\r
93   union {\r
94     ULONGLONG Alignment;\r
95     struct {\r
96       ULONG Length;\r
97       DWORD Reserved;\r
98     };\r
99   };\r
100   struct _IP_ADAPTER_GATEWAY_ADDRESS  *Next;\r
101   SOCKET_ADDRESS                     Address;\r
102 } IP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS, *PIP_ADAPTER_GATEWAY_ADDRESS_LH;\r
103 \r
104 typedef UINT32 NET_IF_COMPARTMENT_ID;\r
105 typedef GUID NET_IF_NETWORK_GUID;\r
106 \r
107 typedef enum _NET_IF_CONNECTION_TYPE {\r
108   NET_IF_CONNECTION_DEDICATED   = 1,\r
109   NET_IF_CONNECTION_PASSIVE,\r
110   NET_IF_CONNECTION_DEMAND,\r
111   NET_IF_CONNECTION_MAXIMUM \r
112 } NET_IF_CONNECTION_TYPE, *PNET_IF_CONNECTION_TYPE;\r
113 \r
114 typedef enum  {\r
115   TUNNEL_TYPE_NONE      = 0,\r
116   TUNNEL_TYPE_OTHER,\r
117   TUNNEL_TYPE_DIRECT,\r
118   TUNNEL_TYPE_6TO4,\r
119   TUNNEL_TYPE_ISATAP,\r
120   TUNNEL_TYPE_TEREDO,\r
121   TUNNEL_TYPE_IPHTTPS \r
122 } TUNNEL_TYPE, *PTUNNEL_TYPE;\r
123 \r
124 /*\r
125 A DUID consists of a two-octet type code represented in network byte\r
126    order, followed by a variable number of octets that make up the\r
127    actual identifier.  A DUID can be no more than 128 octets long (not\r
128    including the type code).\r
129 */\r
130 #define MAX_DHCPV6_DUID_LENGTH 130\r
131 \r
132 typedef union _NET_LUID {\r
133   ULONG64 Value;\r
134   struct {\r
135     ULONG64 Reserved  :24;\r
136     ULONG64 NetLuidIndex  :24;\r
137     ULONG64 IfType  :16;\r
138   } Info;\r
139 } NET_LUID, *PNET_LUID, IF_LUID;\r
140 \r
141 #define MAX_DNS_SUFFIX_STRING_LENGTH 246\r
142 \r
143 typedef struct _IP_ADAPTER_DNS_SUFFIX {\r
144   struct _IP_ADAPTER_DNS_SUFFIX  *Next;\r
145   WCHAR                         String[MAX_DNS_SUFFIX_STRING_LENGTH];\r
146 } IP_ADAPTER_DNS_SUFFIX, *PIP_ADAPTER_DNS_SUFFIX;\r
147 \r
148 \r
149 \r
150 #define _IP_ADAPTER_ADDRESSES_HEAD \\r
151   union { \\r
152     ULONGLONG Alignment; \\r
153     struct { \\r
154       ULONG Length; \\r
155       DWORD IfIndex; \\r
156     }; \\r
157   };\r
158 \r
159 #define _IP_ADAPTER_ADDRESSES_BASE \\r
160   PCHAR                              AdapterName; \\r
161   PIP_ADAPTER_UNICAST_ADDRESS        FirstUnicastAddress; \\r
162   PIP_ADAPTER_ANYCAST_ADDRESS        FirstAnycastAddress; \\r
163   PIP_ADAPTER_MULTICAST_ADDRESS      FirstMulticastAddress; \\r
164   PIP_ADAPTER_DNS_SERVER_ADDRESS     FirstDnsServerAddress; \\r
165   PWCHAR                             DnsSuffix; \\r
166   PWCHAR                             Description; \\r
167   PWCHAR                             FriendlyName; \\r
168   BYTE                               PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; \\r
169   DWORD                              PhysicalAddressLength; \\r
170   DWORD                              Flags; \\r
171   DWORD                              Mtu; \\r
172   DWORD                              IfType; \\r
173   IF_OPER_STATUS                     OperStatus;\r
174 \r
175 #define _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \\r
176   DWORD                              Ipv6IfIndex; \\r
177   DWORD                              ZoneIndices[16]; \\r
178   PIP_ADAPTER_PREFIX                 FirstPrefix; \\r
179 \r
180 \r
181 #define _IP_ADAPTER_ADDRESSES_ADD_VISTA \\r
182   _IP_ADAPTER_ADDRESSES_ADD_XPSP1 \\r
183   ULONG64                            TransmitLinkSpeed; \\r
184   ULONG64                            ReceiveLinkSpeed; \\r
185   PIP_ADAPTER_WINS_SERVER_ADDRESS_LH FirstWinsServerAddress; \\r
186   PIP_ADAPTER_GATEWAY_ADDRESS_LH     FirstGatewayAddress; \\r
187   ULONG                              Ipv4Metric; \\r
188   ULONG                              Ipv6Metric; \\r
189   IF_LUID                            Luid; \\r
190   SOCKET_ADDRESS                     Dhcpv4Server; \\r
191   NET_IF_COMPARTMENT_ID              CompartmentId; \\r
192   NET_IF_NETWORK_GUID                NetworkGuid; \\r
193   NET_IF_CONNECTION_TYPE             ConnectionType; \\r
194   TUNNEL_TYPE                        TunnelType; \\r
195   SOCKET_ADDRESS                     Dhcpv6Server; \\r
196   BYTE                               Dhcpv6ClientDuid[MAX_DHCPV6_DUID_LENGTH]; \\r
197   ULONG                              Dhcpv6ClientDuidLength; \\r
198   ULONG                              Dhcpv6Iaid;\r
199 \r
200 #define _IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1 \\r
201   _IP_ADAPTER_ADDRESSES_ADD_VISTA \\r
202   PIP_ADAPTER_DNS_SUFFIX             FirstDnsSuffix;\r
203 \r
204 #define _IP_ADAPTER_ADDRESSES_DEFINE(suffix,addition) \\r
205 typedef struct _IP_ADAPTER_ADDRESSES##suffix { \\r
206   _IP_ADAPTER_ADDRESSES_HEAD \\r
207   struct _IP_ADAPTER_ADDRESSES##suffix *Next; \\r
208   _IP_ADAPTER_ADDRESSES_BASE \\r
209   addition \\r
210 } IP_ADAPTER_ADDRESSES##suffix, *PIP_ADAPTER_ADDRESSES##suffix;\r
211   \r
212 \r
213 /* _IP_ADAPTER_ADDRESSES_DEFINE(,) defined in w32api headers */\r
214 _IP_ADAPTER_ADDRESSES_DEFINE(_XPSP1,_IP_ADAPTER_ADDRESSES_ADD_XPSP1)\r
215 _IP_ADAPTER_ADDRESSES_DEFINE(_VISTA,_IP_ADAPTER_ADDRESSES_ADD_VISTA)\r
216 _IP_ADAPTER_ADDRESSES_DEFINE(_2008_OR_VISTASP1,_IP_ADAPTER_ADDRESSES_ADD_2008_OR_VISTASP1)\r
217 \r
218 static int\r
219 EnumNICs_IPv6_get_ifs_count (SOCKET s)\r
220 {\r
221   DWORD dwret = 0, err;\r
222   int iret;\r
223   iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0,\r
224       &dwret, NULL, NULL);\r
225   err = GetLastError ();\r
226   if (iret == SOCKET_ERROR && err == WSAEFAULT)\r
227     return dwret;\r
228   else if (iret == 0)\r
229     return 0;\r
230   return GNUNET_SYSERR;\r
231 }\r
232 \r
233 static int\r
234 EnumNICs_IPv6_get_ifs (SOCKET s, SOCKET_ADDRESS_LIST *inf, int size)\r
235 {\r
236   int iret;\r
237   DWORD dwret = 0;\r
238   iret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, inf, size,\r
239       &dwret, NULL, NULL);\r
240 \r
241   if (iret != 0 || dwret != size)\r
242   {\r
243     /* It's supposed to succeed! And size should be the same */\r
244     return GNUNET_SYSERR;\r
245   }\r
246   return GNUNET_OK;\r
247 }\r
248 \r
249 #undef GNUNET_malloc\r
250 #define GNUNET_malloc(a) HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY | \\r
251     HEAP_GENERATE_EXCEPTIONS, a)\r
252 \r
253 #undef GNUNET_free\r
254 #define GNUNET_free(a) HeapFree(GetProcessHeap (), 0, a)\r
255 \r
256 #undef GNUNET_free_non_null\r
257 #define GNUNET_free_non_null(a) do { if ((a) != NULL) GNUNET_free(a); } while (0)\r
258 \r
259 static int\r
260 EnumNICs_IPv4_get_ifs (SOCKET s, INTERFACE_INFO **inf, int *size)\r
261 {\r
262   int iret;\r
263   DWORD dwret = 0;\r
264   DWORD error;\r
265   INTERFACE_INFO *ii = NULL;\r
266   DWORD ii_size = sizeof (INTERFACE_INFO) * 15;\r
267   while (TRUE)\r
268   {\r
269     if (ii_size >= sizeof (INTERFACE_INFO) * 1000)\r
270       return GNUNET_SYSERR;\r
271     ii = (INTERFACE_INFO *) GNUNET_malloc (ii_size);\r
272     dwret = 0;\r
273     iret = WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, ii, ii_size,\r
274         &dwret, NULL, NULL);\r
275     error = GetLastError ();\r
276     if (iret == SOCKET_ERROR)\r
277     {\r
278       if (error == WSAEFAULT)\r
279       {\r
280         GNUNET_free (ii);\r
281         ii_size *= 2;\r
282         continue;\r
283       }\r
284       GNUNET_free (ii);\r
285       return GNUNET_SYSERR;\r
286     }\r
287     else\r
288     {\r
289       *inf = ii;\r
290       *size = dwret;\r
291       return GNUNET_OK;\r
292     }\r
293   }\r
294   return GNUNET_SYSERR;\r
295 }\r
296 \r
297 int\r
298 EnumNICs2 (INTERFACE_INFO **ifs4, int *ifs4_len, SOCKET_ADDRESS_LIST **ifs6)\r
299 {\r
300   int result = 0;\r
301   SOCKET s4 = INVALID_SOCKET, s6 = INVALID_SOCKET;\r
302   DWORD dwret1 = 0, dwret2;\r
303   DWORD err1, err2;\r
304   int ifs4len = 0, ifs6len = 0;\r
305   INTERFACE_INFO *interfaces4 = NULL;\r
306   SOCKET_ADDRESS_LIST *interfaces6 = NULL;\r
307   SetLastError (0);\r
308   s4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);\r
309   err1 = GetLastError ();\r
310   SetLastError (0);\r
311   s6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);\r
312   err2 = GetLastError ();\r
313   if (s6 != INVALID_SOCKET)\r
314   {\r
315     ifs6len = EnumNICs_IPv6_get_ifs_count (s6);\r
316     if (ifs6len > 0)\r
317     {\r
318       interfaces6 = (SOCKET_ADDRESS_LIST *) GNUNET_malloc (ifs6len);\r
319       result = EnumNICs_IPv6_get_ifs (s6, interfaces6, ifs6len) || result;\r
320     }\r
321     closesocket (s6);\r
322     s6 = INVALID_SOCKET;\r
323   }\r
324 \r
325   if (s4 != INVALID_SOCKET)\r
326   {\r
327     result = EnumNICs_IPv4_get_ifs (s4, &interfaces4, &ifs4len) || result;\r
328     closesocket (s4);\r
329     s4 = INVALID_SOCKET;\r
330   }\r
331   if (ifs6len + ifs4len == 0)\r
332     goto error;\r
333 \r
334   if (!result)\r
335   {\r
336     *ifs4 = interfaces4;\r
337     *ifs4_len = ifs4len;\r
338     *ifs6 = interfaces6;\r
339     return GNUNET_OK;\r
340   }\r
341 error:\r
342   if (interfaces4 != NULL)\r
343     GNUNET_free (interfaces4);\r
344   if (interfaces6 != NULL)\r
345     GNUNET_free (interfaces6);\r
346   if (s4 != INVALID_SOCKET)\r
347     closesocket (s4);\r
348   if (s6 != INVALID_SOCKET)\r
349     closesocket (s6);\r
350   return GNUNET_SYSERR;\r
351 }\r
352 \r
353 /**\r
354  * Returns GNUNET_OK on OK, GNUNET_SYSERR on error\r
355  */\r
356 int\r
357 EnumNICs3 (struct EnumNICs3_results **results, int *results_count)\r
358 {\r
359   DWORD dwRetVal = 0;\r
360   int count = 0;\r
361   ULONG flags = /*GAA_FLAG_INCLUDE_PREFIX |*/ GAA_FLAG_SKIP_ANYCAST |\r
362       GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;\r
363   struct sockaddr_in6 examplecom6;\r
364   IPAddr examplecom;\r
365   DWORD best_interface = 0;\r
366   DWORD best_interface6 = 0;\r
367 \r
368   int use_enum2 = 0;\r
369   INTERFACE_INFO *interfaces4 = NULL;\r
370   int interfaces4_len = 0;\r
371   SOCKET_ADDRESS_LIST *interfaces6 = NULL;\r
372 \r
373   unsigned long outBufLen = sizeof (IP_ADAPTER_ADDRESSES);\r
374   IP_ADAPTER_ADDRESSES *pCurrentAddress = NULL;\r
375   IP_ADAPTER_ADDRESSES *pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);\r
376 \r
377   if (GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen)\r
378       == ERROR_BUFFER_OVERFLOW)\r
379   {\r
380     GNUNET_free (pAddresses);\r
381     pAddresses = (IP_ADAPTER_ADDRESSES *) GNUNET_malloc (outBufLen);\r
382   }\r
383 \r
384   dwRetVal = GetAdaptersAddresses (AF_UNSPEC, flags, NULL, pAddresses, &outBufLen);\r
385 \r
386   if (dwRetVal != NO_ERROR)\r
387   {\r
388     GNUNET_free (pAddresses);\r
389     return GNUNET_SYSERR;\r
390   }\r
391 \r
392   if (pAddresses->Length < sizeof (IP_ADAPTER_ADDRESSES_VISTA))\r
393   {\r
394     use_enum2 = 1;\r
395 \r
396     /* Enumerate NICs using WSAIoctl() */\r
397     if (GNUNET_OK != EnumNICs2 (&interfaces4, &interfaces4_len, &interfaces6))\r
398     {\r
399       GNUNET_free (pAddresses);\r
400       return GNUNET_SYSERR;\r
401     }\r
402   }\r
403 \r
404   examplecom = inet_addr("192.0.34.166"); /* www.example.com */\r
405   if (GetBestInterface (examplecom, &best_interface) != NO_ERROR)\r
406     best_interface = 0;\r
407 \r
408   if (GNGetBestInterfaceEx != NULL)\r
409   {\r
410     examplecom6.sin6_family = AF_INET6;\r
411     examplecom6.sin6_port = 0;\r
412     examplecom6.sin6_flowinfo = 0;\r
413     examplecom6.sin6_scope_id = 0;\r
414     inet_pton (AF_INET6, "2001:500:88:200:0:0:0:10",\r
415         (struct sockaddr *) &examplecom6.sin6_addr);\r
416     dwRetVal = GNGetBestInterfaceEx ((struct sockaddr *) &examplecom6,\r
417         &best_interface6);\r
418     if (dwRetVal != NO_ERROR)\r
419       best_interface6 = 0;\r
420   }\r
421 \r
422   /* Give IPv6 a priority */\r
423   if (best_interface6 != 0)\r
424     best_interface = best_interface6;\r
425 \r
426   count = 0;\r
427   for (pCurrentAddress = pAddresses;\r
428       pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)\r
429   {\r
430     if (pCurrentAddress->OperStatus == IfOperStatusUp)\r
431     {\r
432       IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;\r
433       for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;\r
434           unicast = unicast->Next)\r
435       {\r
436         if ((unicast->Address.lpSockaddr->sa_family == AF_INET ||\r
437             unicast->Address.lpSockaddr->sa_family == AF_INET6) &&\r
438             (unicast->DadState == IpDadStateDeprecated ||\r
439             unicast->DadState == IpDadStatePreferred))\r
440           count += 1;\r
441       }\r
442     }\r
443   }\r
444 \r
445   if (count == 0)\r
446   {\r
447     *results = NULL;\r
448     *results_count = 0;\r
449     GNUNET_free (pAddresses);\r
450     GNUNET_free_non_null (interfaces4);\r
451     GNUNET_free_non_null (interfaces6);\r
452     return GNUNET_OK;\r
453   }\r
454 \r
455   *results = (struct EnumNICs3_results *) GNUNET_malloc (\r
456       sizeof (struct EnumNICs3_results) * count);\r
457   *results_count = count;\r
458 \r
459   count = 0;\r
460   for (pCurrentAddress = pAddresses;\r
461       pCurrentAddress != NULL; pCurrentAddress = pCurrentAddress->Next)\r
462   {\r
463     struct EnumNICs3_results *r;\r
464     IP_ADAPTER_UNICAST_ADDRESS *unicast = NULL;\r
465     if (pCurrentAddress->OperStatus != IfOperStatusUp)\r
466       continue;\r
467     for (unicast = pCurrentAddress->FirstUnicastAddress; unicast != NULL;\r
468         unicast = unicast->Next)\r
469     {\r
470       int i, j;\r
471       int mask_length = -1;\r
472       char dst[INET6_ADDRSTRLEN + 1];\r
473 \r
474       if ((unicast->Address.lpSockaddr->sa_family != AF_INET &&\r
475           unicast->Address.lpSockaddr->sa_family != AF_INET6) ||\r
476           (unicast->DadState != IpDadStateDeprecated &&\r
477           unicast->DadState != IpDadStatePreferred))\r
478         continue;\r
479 \r
480       r = &(*results)[count];\r
481       r->flags = 0;\r
482       if (pCurrentAddress->IfIndex > 0 &&\r
483           pCurrentAddress->IfIndex == best_interface &&\r
484           unicast->Address.lpSockaddr->sa_family == AF_INET)\r
485         r->is_default = 1;\r
486       else if (pCurrentAddress->Ipv6IfIndex > 0 &&\r
487           pCurrentAddress->Ipv6IfIndex == best_interface6 &&\r
488           unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
489         r->is_default = 1;\r
490       else\r
491         r->is_default = 0;\r
492 \r
493       /* Don't choose default interface twice */\r
494       if (r->is_default)\r
495         best_interface = best_interface6 = 0;\r
496 \r
497       if (!use_enum2)\r
498       {\r
499         memcpy (&r->address, unicast->Address.lpSockaddr,\r
500             unicast->Address.iSockaddrLength);\r
501         memset (&r->mask, 0, sizeof (struct sockaddr));\r
502         mask_length = ((IP_ADAPTER_UNICAST_ADDRESS_VISTA *) unicast)->\r
503               OnLinkPrefixLength;\r
504         /* OnLinkPrefixLength is the number of leading 1s in the mask.\r
505          * OnLinkPrefixLength is available on Vista and later (hence use_enum2).\r
506          */\r
507         if (unicast->Address.lpSockaddr->sa_family == AF_INET)\r
508         {\r
509           struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;\r
510           for (i = 0; i < mask_length; i++)\r
511               ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);\r
512         }\r
513         else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
514         {\r
515           struct sockaddr_in6 *m = (struct sockaddr_in6 *) &r->mask;\r
516           struct sockaddr_in6 *b = (struct sockaddr_in6 *) &r->broadcast;\r
517           for (i = 0; i < mask_length; i++)\r
518             ((unsigned char *) &m->sin6_addr)[i / 8] |= 0x80 >> (i % 8);\r
519           memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);\r
520           for (i = mask_length; i < 128; i++)\r
521             ((unsigned char *) &b->sin6_addr)[i / 8] |= 0x80 >> (i % 8);\r
522         }\r
523         r->flags |= ENUMNICS3_MASK_OK;\r
524       }\r
525       else\r
526       {\r
527         int found = 0;\r
528         if (unicast->Address.lpSockaddr->sa_family == AF_INET)\r
529         {\r
530           for (i = 0; !found && i < interfaces4_len / sizeof (INTERFACE_INFO); i++)\r
531           {\r
532             struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;\r
533             if (memcpy (&interfaces4[i].iiAddress.Address,\r
534                 unicast->Address.lpSockaddr,\r
535                 unicast->Address.iSockaddrLength) != 0)\r
536               continue;\r
537             found = 1;\r
538             memcpy (&r->address, &interfaces4[i].iiAddress.Address,\r
539                 sizeof (struct sockaddr_in));\r
540             memcpy (&r->mask, &interfaces4[i].iiNetmask.Address,\r
541                 sizeof (struct sockaddr_in));\r
542             for (mask_length = 0;\r
543                 ((unsigned char *) &m->sin_addr)[mask_length / 8] &\r
544                 0x80 >> (mask_length % 8); mask_length++)\r
545             {\r
546             }\r
547             r->flags |= ENUMNICS3_MASK_OK;\r
548           }\r
549         }\r
550         else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
551         {\r
552           for (i = 0;\r
553               interfaces6 != NULL && !found && i < interfaces6->iAddressCount;\r
554               i++)\r
555           {\r
556             if (memcpy (interfaces6->Address[i].lpSockaddr,\r
557                 unicast->Address.lpSockaddr,\r
558                 unicast->Address.iSockaddrLength) != 0)\r
559               continue;\r
560             found = 1;\r
561             memcpy (&r->address, interfaces6->Address[i].lpSockaddr,\r
562                 sizeof (struct sockaddr_in6));\r
563             /* TODO: Find a way to reliably get network mask for IPv6 on XP */\r
564             memset (&r->mask, 0, sizeof (struct sockaddr));\r
565             r->flags &= ~ENUMNICS3_MASK_OK;\r
566           }\r
567         }\r
568         if (!found)\r
569         {\r
570           DebugBreak ();\r
571         }\r
572       }\r
573       if (unicast->Address.lpSockaddr->sa_family == AF_INET)\r
574       {\r
575         struct sockaddr_in *m = (struct sockaddr_in *) &r->mask;\r
576         struct sockaddr_in *a = (struct sockaddr_in *) &r->address;\r
577         /* copy address to broadcast, then flip all the trailing bits not\r
578          * falling under netmask to 1,\r
579          * so we get, 192.168.0.255 from, say, 192.168.0.43 with mask == 24.\r
580          */\r
581         memcpy (&r->broadcast, &r->address, unicast->Address.iSockaddrLength);\r
582         for (i = mask_length; i < 32; i++)\r
583           ((unsigned char *) &m->sin_addr)[i / 8] |= 0x80 >> (i % 8);\r
584         r->flags |= ENUMNICS3_BCAST_OK;\r
585         r->addr_size = sizeof (struct sockaddr_in);\r
586         inet_ntop (AF_INET, &a->sin_addr, dst, INET_ADDRSTRLEN);\r
587       }\r
588       else if (unicast->Address.lpSockaddr->sa_family == AF_INET6)\r
589       {\r
590         struct sockaddr_in6 *a = (struct sockaddr_in6 *) &r->address;\r
591         /* for IPv6 broadcast is not defined, zero it down */\r
592         memset (&r->broadcast, 0, sizeof (struct sockaddr));\r
593         r->flags &= ~ENUMNICS3_BCAST_OK;\r
594         r->addr_size = sizeof (struct sockaddr_in6);\r
595         inet_ntop (AF_INET6, &a->sin6_addr, dst, INET6_ADDRSTRLEN);\r
596       }\r
597 \r
598       i = 0;\r
599       i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,\r
600           "%S (%s", pCurrentAddress->FriendlyName, dst);\r
601       for (j = 0; j < pCurrentAddress->PhysicalAddressLength; j++)\r
602         i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0,\r
603             "%s%02X",j > 0 ? ":" : " - ", pCurrentAddress->PhysicalAddress[j]);\r
604       i += snprintf (&r->pretty_name[i], 1000 - i > 0 ? 1000 - i : 0, ")");\r
605       r->pretty_name[1000] = '\0';\r
606       count += 1;\r
607     }\r
608   }\r
609 \r
610   if (use_enum2)\r
611   {\r
612     GNUNET_free_non_null (interfaces4);\r
613     GNUNET_free_non_null (interfaces6);\r
614   }\r
615 \r
616   GNUNET_free (pAddresses);\r
617   return GNUNET_OK;\r
618 }\r
619 \r
620 void\r
621 EnumNICs3_free (struct EnumNICs3_results *r)\r
622 {\r
623   GNUNET_free_non_null (r);\r
624 }\r
625 \r
626 \r
627 /**\r
628  * Lists all network interfaces in a combo box\r
629  * Used by the basic GTK configurator\r
630  *\r
631  * @param callback function to call for each NIC\r
632  * @param callback_cls closure for callback\r
633  */\r
634 int\r
635 ListNICs (void (*callback) (void *, const char *, int), void * callback_cls)\r
636 {\r
637   int r;\r
638   int i;\r
639   struct EnumNICs3_results *results = NULL;\r
640   int results_count;\r
641 \r
642   r = EnumNICs3 (&results, &results_count);\r
643   if (r != GNUNET_OK)\r
644     return GNUNET_NO;\r
645 \r
646   for (i = 0; i < results_count; i++)\r
647     callback (callback_cls, results[i].pretty_name, results[i].is_default);\r
648   GNUNET_free_non_null (results);\r
649   return GNUNET_YES;\r
650 }\r
651 \r
652 /**\r
653  * @brief Installs the Windows service\r
654  * @param servicename name of the service as diplayed by the SCM\r
655  * @param application path to the application binary\r
656  * @param username the name of the service's user account\r
657  * @returns 0 on success\r
658  *          1 if the Windows version doesn't support services\r
659  *          2 if the SCM could not be opened\r
660  *          3 if the service could not be created\r
661  */\r
662 int InstallAsService(char *servicename, char *application, char *username)\r
663 {\r
664   SC_HANDLE hManager, hService;\r
665   char szEXE[_MAX_PATH + 17] = "\"";\r
666   char *user = NULL;\r
667 \r
668   if (! GNOpenSCManager)\r
669     return 1;\r
670 \r
671   plibc_conv_to_win_path(application, szEXE + 1);\r
672   strcat(szEXE, "\" --win-service");\r
673   hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);\r
674   if (! hManager)\r
675     return 2;\r
676 \r
677   if (username)\r
678   {\r
679         user = (char *) malloc(strlen(username) + 3);\r
680         sprintf(user, ".\\%s", username);\r
681   }\r
682 \r
683   hService = GNCreateService(hManager, (LPCTSTR) servicename, (LPCTSTR) servicename, 0,\r
684     SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, (LPCTSTR) szEXE,\r
685     NULL, NULL, NULL, (LPCTSTR) user, (LPCTSTR) username);\r
686 \r
687   if (user)\r
688     free(user);\r
689 \r
690   if (! hService)\r
691     return 3;\r
692 \r
693   GNCloseServiceHandle(hService);\r
694 \r
695   return 0;\r
696 }\r
697 \r
698 /**\r
699  * @brief Uninstall Windows service\r
700  * @param servicename name of the service to delete\r
701  * @returns 0 on success\r
702  *          1 if the Windows version doesn't support services\r
703  *          2 if the SCM could not be openend\r
704  *          3 if the service cannot be accessed\r
705  *          4 if the service cannot be deleted\r
706  */\r
707 int UninstallService(char *servicename)\r
708 {\r
709   SC_HANDLE hManager, hService;\r
710 \r
711   if (! GNOpenSCManager)\r
712     return 1;\r
713 \r
714   hManager = GNOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);\r
715   if (! hManager)\r
716     return 2;\r
717 \r
718   if (! (hService = GNOpenService(hManager, (LPCTSTR) servicename, DELETE)))\r
719     if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)\r
720       return 3;\r
721      else\r
722         goto closeSCM;\r
723 \r
724   if (! GNDeleteService(hService))\r
725     if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)\r
726       return 4;\r
727 \r
728 closeSCM:\r
729   GNCloseServiceHandle(hService);\r
730 \r
731   return 0;\r
732 }\r
733 \r
734 /**\r
735  * @author Scott Field, Microsoft\r
736  * @see http://support.microsoft.com/?scid=kb;en-us;132958\r
737  * @date 12-Jul-95\r
738  */\r
739 void _InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)\r
740 {\r
741   DWORD StringLength;\r
742 \r
743   if(String == NULL)\r
744   {\r
745     LsaString->Buffer = NULL;\r
746     LsaString->Length = 0;\r
747     LsaString->MaximumLength = 0;\r
748     return;\r
749   }\r
750 \r
751   StringLength = wcslen(String);\r
752   LsaString->Buffer = String;\r
753   LsaString->Length = (USHORT) StringLength *sizeof(WCHAR);\r
754   LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);\r
755 }\r
756 \r
757 \r
758 /**\r
759  * @author Scott Field, Microsoft\r
760  * @see http://support.microsoft.com/?scid=kb;en-us;132958\r
761  * @date 12-Jul-95\r
762  */\r
763 NTSTATUS _OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)\r
764 {\r
765   LSA_OBJECT_ATTRIBUTES ObjectAttributes;\r
766   LSA_UNICODE_STRING ServerString;\r
767   PLSA_UNICODE_STRING Server = NULL;\r
768 \r
769   /* Always initialize the object attributes to all zeroes. */\r
770   ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));\r
771 \r
772   if(ServerName != NULL)\r
773   {\r
774     /* Make a LSA_UNICODE_STRING out of the LPWSTR passed in */\r
775     _InitLsaString(&ServerString, ServerName);\r
776     Server = &ServerString;\r
777   }\r
778 \r
779   /* Attempt to open the policy. */\r
780   return GNLsaOpenPolicy(Server,\r
781                        &ObjectAttributes, DesiredAccess, PolicyHandle);\r
782 }\r
783 \r
784 /**\r
785  * @brief Obtain a SID representing the supplied account on the supplied system\r
786  * @return TRUE on success, FALSE on failure\r
787  * @author Scott Field, Microsoft\r
788  * @date 12-Jul-95\r
789  * @remarks A buffer is allocated which contains the SID representing the\r
790  *          supplied account. This buffer should be freed when it is no longer\r
791  *          needed by calling\n\r
792  *            HeapFree(GetProcessHeap(), 0, buffer)\r
793  * @remarks Call GetLastError() to obtain extended error information.\r
794  * @see http://support.microsoft.com/?scid=kb;en-us;132958\r
795  */\r
796 BOOL _GetAccountSid(LPCTSTR SystemName, LPCTSTR AccountName, PSID * Sid)\r
797 {\r
798   LPTSTR ReferencedDomain = NULL;\r
799   DWORD cbSid = 128;                                                    /* initial allocation attempt */\r
800   DWORD cchReferencedDomain = 16;       /* initial allocation size */\r
801   SID_NAME_USE peUse;\r
802   BOOL bSuccess = FALSE;                                        /* assume this function will fail */\r
803 \r
804   /* initial memory allocations */\r
805   if ((*Sid = HeapAlloc (GetProcessHeap (), 0, cbSid)) == NULL)\r
806         return FALSE;\r
807 \r
808   if ((ReferencedDomain = (LPTSTR) HeapAlloc (GetProcessHeap (),\r
809                                     0,\r
810                                     cchReferencedDomain *\r
811                                     sizeof (TCHAR))) == NULL)\r
812         return FALSE;\r
813 \r
814     /* Obtain the SID of the specified account on the specified system. */\r
815         while (!GNLookupAccountName(SystemName, /* machine to lookup account on */\r
816                    AccountName,                                                                                         /* account to lookup */\r
817                    *Sid,                                                                                                                        /* SID of interest */\r
818                    &cbSid,                                                                                                              /* size of SID */\r
819                    ReferencedDomain,                                                                    /* domain account was found on */\r
820                    &cchReferencedDomain, &peUse))\r
821         {\r
822                 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)\r
823                 {\r
824                         /* reallocate memory */\r
825                         if ((*Sid = HeapReAlloc (GetProcessHeap (), 0, *Sid, cbSid)) == NULL)\r
826                                 return FALSE;\r
827 \r
828                         if ((ReferencedDomain = (LPTSTR) HeapReAlloc (GetProcessHeap (),\r
829                                               0,\r
830                                               ReferencedDomain,\r
831                                               cchReferencedDomain\r
832                                               * sizeof (TCHAR))) == NULL)\r
833                                 return FALSE;\r
834       }\r
835       else\r
836         goto end;\r
837   }\r
838 \r
839   /* Indicate success. */\r
840   bSuccess = TRUE;\r
841 \r
842 end:\r
843   /* Cleanup and indicate failure, if appropriate. */\r
844   HeapFree (GetProcessHeap (), 0, ReferencedDomain);\r
845 \r
846   if (!bSuccess)\r
847   {\r
848     if (*Sid != NULL)\r
849     {\r
850                 HeapFree (GetProcessHeap (), 0, *Sid);\r
851                 *Sid = NULL;\r
852     }\r
853   }\r
854 \r
855   return bSuccess;\r
856 }\r
857 \r
858 /**\r
859  * @author Scott Field, Microsoft\r
860  * @see http://support.microsoft.com/?scid=kb;en-us;132958\r
861  * @date 12-Jul-95\r
862  */\r
863 NTSTATUS _SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle,/* open policy handle */\r
864                                PSID AccountSid,                         /* SID to grant privilege to */\r
865                                LPWSTR PrivilegeName,    /* privilege to grant (Unicode) */\r
866                                BOOL bEnable                                             /* enable or disable */\r
867   )\r
868 {\r
869   LSA_UNICODE_STRING PrivilegeString;\r
870 \r
871   /* Create a LSA_UNICODE_STRING for the privilege name. */\r
872   _InitLsaString(&PrivilegeString, PrivilegeName);\r
873 \r
874   /* grant or revoke the privilege, accordingly */\r
875   if(bEnable)\r
876   {\r
877     NTSTATUS i;\r
878 \r
879     i = GNLsaAddAccountRights(PolicyHandle,                             /* open policy handle */\r
880                                AccountSid,                              /* target SID */\r
881                                &PrivilegeString,        /* privileges */\r
882                                1                                                                                        /* privilege count */\r
883       );\r
884   }\r
885   else\r
886   {\r
887     return GNLsaRemoveAccountRights(PolicyHandle,                       /* open policy handle */\r
888                                   AccountSid,                           /* target SID */\r
889                                   FALSE,                                                        /* do not disable all rights */\r
890                                   &PrivilegeString,             /* privileges */\r
891                                   1                                                                             /* privilege count */\r
892       );\r
893   }\r
894 }\r
895 \r
896 /**\r
897  * @brief Create a Windows service account\r
898  * @return 0 on success, > 0 otherwise\r
899  * @param pszName the name of the account\r
900  * @param pszDesc description of the account\r
901  */\r
902 int CreateServiceAccount(const char *pszName, const char *pszDesc)\r
903 {\r
904   USER_INFO_1 ui;\r
905   USER_INFO_1008 ui2;\r
906   NET_API_STATUS nStatus;\r
907   wchar_t wszName[MAX_NAME_LENGTH], wszDesc[MAX_NAME_LENGTH];\r
908   DWORD dwErr;\r
909   LSA_HANDLE hPolicy;\r
910   PSID pSID;\r
911 \r
912   if (! GNNetUserAdd)\r
913         return 1;\r
914   mbstowcs(wszName, pszName, strlen(pszName) + 1);\r
915   mbstowcs(wszDesc, pszDesc, strlen(pszDesc) + 1);\r
916 \r
917   memset(&ui, 0, sizeof(ui));\r
918   ui.usri1_name = wszName;\r
919   ui.usri1_password = wszName; /* account is locked anyway */\r
920   ui.usri1_priv = USER_PRIV_USER;\r
921   ui.usri1_comment = wszDesc;\r
922   ui.usri1_flags = UF_SCRIPT;\r
923 \r
924   nStatus = GNNetUserAdd(NULL, 1, (LPBYTE)&ui, NULL);\r
925 \r
926   if (nStatus != NERR_Success && nStatus != NERR_UserExists)\r
927         return 2;\r
928 \r
929   ui2.usri1008_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;\r
930   GNNetUserSetInfo(NULL, wszName, 1008, (LPBYTE)&ui2, NULL);\r
931 \r
932   if (_OpenPolicy(NULL, POLICY_ALL_ACCESS, &hPolicy) !=\r
933                                                                                 STATUS_SUCCESS)\r
934         return 3;\r
935 \r
936   _GetAccountSid(NULL, (LPCTSTR) pszName, &pSID);\r
937 \r
938   if (_SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeServiceLogonRight", TRUE) != STATUS_SUCCESS)\r
939         return 4;\r
940 \r
941   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyInteractiveLogonRight", TRUE);\r
942   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyBatchLogonRight", TRUE);\r
943   _SetPrivilegeOnAccount(hPolicy, pSID, (LPWSTR) L"SeDenyNetworkLogonRight", TRUE);\r
944 \r
945   GNLsaClose(hPolicy);\r
946 \r
947   return 0;\r
948 }\r
949 \r
950 /**\r
951  * @brief Grant permission to a file\r
952  * @param lpszFileName the name of the file or directory\r
953  * @param lpszAccountName the user account\r
954  * @param dwAccessMask the desired access (e.g. GENERIC_ALL)\r
955  * @return TRUE on success\r
956  * @remark based on http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q102102&\r
957  */\r
958 BOOL AddPathAccessRights(char *lpszFileName, char *lpszAccountName,\r
959       DWORD dwAccessMask)\r
960 {\r
961   /* SID variables. */\r
962   SID_NAME_USE   snuType;\r
963   TCHAR *        szDomain       = NULL;\r
964   DWORD          cbDomain       = 0;\r
965   LPVOID         pUserSID       = NULL;\r
966   DWORD          cbUserSID      = 0;\r
967 \r
968   /* File SD variables. */\r
969   PSECURITY_DESCRIPTOR pFileSD  = NULL;\r
970   DWORD          cbFileSD       = 0;\r
971 \r
972   /* New SD variables. */\r
973   SECURITY_DESCRIPTOR  newSD;\r
974 \r
975   /* ACL variables. */\r
976   PACL           pACL           = NULL;\r
977   BOOL           fDaclPresent;\r
978   BOOL           fDaclDefaulted;\r
979   ACL_SIZE_INFORMATION AclInfo;\r
980 \r
981   /* New ACL variables. */\r
982   PACL           pNewACL        = NULL;\r
983   DWORD          cbNewACL       = 0;\r
984 \r
985   /* Temporary ACE. */\r
986   LPVOID         pTempAce       = NULL;\r
987   UINT           CurrentAceIndex = 0;\r
988 \r
989   UINT           newAceIndex = 0;\r
990 \r
991   /* Assume function will fail. */\r
992   BOOL           fResult        = FALSE;\r
993   BOOL           fAPISuccess;\r
994 \r
995   SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;\r
996 \r
997   /**\r
998    * STEP 1: Get SID of the account name specified.\r
999    */\r
1000   fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,\r
1001         pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);\r
1002 \r
1003   /* API should have failed with insufficient buffer. */\r
1004   if (fAPISuccess)\r
1005      goto end;\r
1006   else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {\r
1007      goto end;\r
1008   }\r
1009 \r
1010   pUserSID = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbUserSID);\r
1011   if (!pUserSID) {\r
1012      goto end;\r
1013   }\r
1014 \r
1015   szDomain = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDomain * sizeof(TCHAR));\r
1016   if (!szDomain) {\r
1017      goto end;\r
1018   }\r
1019 \r
1020   fAPISuccess = GNLookupAccountName(NULL, (LPCTSTR) lpszAccountName,\r
1021         pUserSID, &cbUserSID, (LPTSTR) szDomain, &cbDomain, &snuType);\r
1022   if (!fAPISuccess) {\r
1023      goto end;\r
1024   }\r
1025 \r
1026   /**\r
1027    *  STEP 2: Get security descriptor (SD) of the file specified.\r
1028    */\r
1029   fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,\r
1030         secInfo, pFileSD, 0, &cbFileSD);\r
1031 \r
1032   /* API should have failed with insufficient buffer. */\r
1033   if (fAPISuccess)\r
1034      goto end;\r
1035   else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {\r
1036      goto end;\r
1037   }\r
1038 \r
1039   pFileSD = (PSECURITY_DESCRIPTOR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,\r
1040         cbFileSD);\r
1041   if (!pFileSD) {\r
1042      goto end;\r
1043   }\r
1044 \r
1045   fAPISuccess = GNGetFileSecurity((LPCTSTR) lpszFileName,\r
1046         secInfo, pFileSD, cbFileSD, &cbFileSD);\r
1047   if (!fAPISuccess) {\r
1048      goto end;\r
1049   }\r
1050 \r
1051   /**\r
1052    * STEP 3: Initialize new SD.\r
1053    */\r
1054   if (!GNInitializeSecurityDescriptor(&newSD,\r
1055         SECURITY_DESCRIPTOR_REVISION)) {\r
1056      goto end;\r
1057   }\r
1058 \r
1059   /**\r
1060    * STEP 4: Get DACL from the old SD.\r
1061    */\r
1062   if (!GNGetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,\r
1063         &fDaclDefaulted)) {\r
1064      goto end;\r
1065   }\r
1066 \r
1067   /**\r
1068    * STEP 5: Get size information for DACL.\r
1069    */\r
1070   AclInfo.AceCount = 0; // Assume NULL DACL.\r
1071   AclInfo.AclBytesFree = 0;\r
1072   AclInfo.AclBytesInUse = sizeof(ACL);\r
1073 \r
1074   if (pACL == NULL)\r
1075      fDaclPresent = FALSE;\r
1076 \r
1077   /* If not NULL DACL, gather size information from DACL. */\r
1078   if (fDaclPresent) {\r
1079 \r
1080      if (!GNGetAclInformation(pACL, &AclInfo,\r
1081            sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {\r
1082         goto end;\r
1083      }\r
1084   }\r
1085 \r
1086   /**\r
1087    * STEP 6: Compute size needed for the new ACL.\r
1088    */\r
1089   cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)\r
1090         + GetLengthSid(pUserSID) - sizeof(DWORD);\r
1091 \r
1092   /**\r
1093    * STEP 7: Allocate memory for new ACL.\r
1094    */\r
1095   pNewACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNewACL);\r
1096   if (!pNewACL) {\r
1097      goto end;\r
1098   }\r
1099 \r
1100   /**\r
1101    * STEP 8: Initialize the new ACL.\r
1102    */\r
1103   if (!GNInitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {\r
1104      goto end;\r
1105   }\r
1106 \r
1107   /**\r
1108    * STEP 9 If DACL is present, copy all the ACEs from the old DACL\r
1109    * to the new DACL.\r
1110    *\r
1111    * The following code assumes that the old DACL is\r
1112    * already in Windows 2000 preferred order.  To conform\r
1113    * to the new Windows 2000 preferred order, first we will\r
1114    * copy all non-inherited ACEs from the old DACL to the\r
1115    * new DACL, irrespective of the ACE type.\r
1116    */\r
1117 \r
1118   newAceIndex = 0;\r
1119 \r
1120   if (fDaclPresent && AclInfo.AceCount) {\r
1121 \r
1122      for (CurrentAceIndex = 0;\r
1123            CurrentAceIndex < AclInfo.AceCount;\r
1124            CurrentAceIndex++) {\r
1125 \r
1126         /**\r
1127          * TEP 10: Get an ACE.\r
1128          */\r
1129         if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {\r
1130            goto end;\r
1131         }\r
1132 \r
1133         /**\r
1134          * STEP 11: Check if it is a non-inherited ACE.\r
1135          * If it is an inherited ACE, break from the loop so\r
1136          * that the new access allowed non-inherited ACE can\r
1137          * be added in the correct position, immediately after\r
1138          * all non-inherited ACEs.\r
1139          */\r
1140         if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags\r
1141            & INHERITED_ACE)\r
1142            break;\r
1143 \r
1144         /**\r
1145          * STEP 12: Skip adding the ACE, if the SID matches\r
1146          * with the account specified, as we are going to\r
1147          * add an access allowed ACE with a different access\r
1148          * mask.\r
1149          */\r
1150         if (GNEqualSid(pUserSID,\r
1151            &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))\r
1152            continue;\r
1153 \r
1154         /**\r
1155          * STEP 13: Add the ACE to the new ACL.\r
1156          */\r
1157         if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,\r
1158               ((PACE_HEADER) pTempAce)->AceSize)) {\r
1159            goto end;\r
1160         }\r
1161 \r
1162         newAceIndex++;\r
1163      }\r
1164   }\r
1165 \r
1166   /**\r
1167    * STEP 14: Add the access-allowed ACE to the new DACL.\r
1168    * The new ACE added here will be in the correct position,\r
1169    * immediately after all existing non-inherited ACEs.\r
1170    */\r
1171   if (!GNAddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask,\r
1172         pUserSID)) {\r
1173      goto end;\r
1174   }\r
1175 \r
1176   /**\r
1177    * STEP 14.5: Make new ACE inheritable\r
1178    */\r
1179   if (!GetAce(pNewACL, newAceIndex, &pTempAce))\r
1180     goto end;\r
1181   ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags |=\r
1182     (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);\r
1183 \r
1184   /**\r
1185    * STEP 15: To conform to the new Windows 2000 preferred order,\r
1186    * we will now copy the rest of inherited ACEs from the\r
1187    * old DACL to the new DACL.\r
1188    */\r
1189   if (fDaclPresent && AclInfo.AceCount) {\r
1190 \r
1191      for (;\r
1192           CurrentAceIndex < AclInfo.AceCount;\r
1193           CurrentAceIndex++) {\r
1194 \r
1195         /**\r
1196          * STEP 16: Get an ACE.\r
1197          */\r
1198         if (!GNGetAce(pACL, CurrentAceIndex, &pTempAce)) {\r
1199            goto end;\r
1200         }\r
1201 \r
1202         /**\r
1203          * STEP 17: Add the ACE to the new ACL.\r
1204          */\r
1205         if (!GNAddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,\r
1206               ((PACE_HEADER) pTempAce)->AceSize)) {\r
1207            goto end;\r
1208         }\r
1209      }\r
1210   }\r
1211 \r
1212   /**\r
1213    * STEP 18: Set permissions\r
1214    */\r
1215   if (GNSetNamedSecurityInfo((LPTSTR) lpszFileName, SE_FILE_OBJECT,\r
1216     DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) {\r
1217         goto end;\r
1218   }\r
1219 \r
1220   fResult = TRUE;\r
1221 \r
1222 end:\r
1223 \r
1224   /**\r
1225    * STEP 19: Free allocated memory\r
1226    */\r
1227   if (pUserSID)\r
1228      HeapFree(GetProcessHeap(), 0, pUserSID);\r
1229 \r
1230   if (szDomain)\r
1231      HeapFree(GetProcessHeap(), 0, szDomain);\r
1232 \r
1233   if (pFileSD)\r
1234      HeapFree(GetProcessHeap(), 0, pFileSD);\r
1235 \r
1236   if (pNewACL)\r
1237      HeapFree(GetProcessHeap(), 0, pNewACL);\r
1238 \r
1239   return fResult;\r
1240 }\r
1241 \r
1242 char *winErrorStr(const char *prefix, int dwErr)\r
1243 {\r
1244   char *err, *ret;\r
1245   int mem;\r
1246 \r
1247   if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,\r
1248     NULL, (DWORD) dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err,\r
1249     0, NULL ))\r
1250   {\r
1251     err = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 1);\r
1252   }\r
1253 \r
1254   mem = strlen(err) + strlen(prefix) + 20;\r
1255   ret = (char *) malloc(mem);\r
1256 \r
1257   snprintf(ret, mem, "%s: %s (#%u)", prefix, err, dwErr);\r
1258 \r
1259   LocalFree(err);\r
1260 \r
1261   return ret;\r
1262 }\r
1263 \r
1264 } /* extern "C" */\r
1265 \r
1266 #endif\r