2 * Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // privPortClient - Authorization privileged-port binding client side
22 #include <Security/AuthorizationPriv.h>
23 #include <Security/fdmover.h>
24 #include <Security/debugging.h>
27 using namespace UnixPlusPlus
;
28 using namespace IPPlusPlus
;
32 // Where is the trampoline itself?
34 #if !defined(PORTSERVERPATH)
35 # define PORTSERVERPATH "/System/Library/CoreServices/privportserver" /* fallback */
42 static void startServer();
46 // The official client function. This does all the work
48 OSStatus
AuthorizationBindPrivilegedPort(int fileDescriptor
,
49 const struct sockaddr_in
*name
,
50 AuthorizationRef authorization
,
51 AuthorizationFlags flags
)
54 unsigned short port
= ntohs(name
->sin_port
);
55 secdebug("portserve", "bind request fd=%d port=%d", fileDescriptor
, port
);
57 // must request a privileged port (don't check for debug version)
59 if (port
<= 0 || port
>= IPPORT_RESERVED
)
60 return errAuthorizationBadAddress
;
63 // no flags recognized so far
65 return errAuthorizationInvalidFlags
;
67 // form the request message
69 if (OSStatus err
= AuthorizationMakeExternalForm(authorization
, &request
.authForm
))
71 request
.requestedName
= *name
;
73 // connect to the port server (start it if we must)
74 UNSockAddress
serverAddress(kPrivilegedPortBinder
);
76 server
.open(AF_UNIX
, SOCK_STREAM
);
78 server
.connect(serverAddress
);
79 } catch (const UnixError
&error
) {
80 switch (error
.error
) {
81 case ENOENT
: // not bound
82 case ECONNREFUSED
: // was bound, server is dead
84 server
.connect(serverAddress
);
92 secdebug("portserve", "sending request");
94 fds
.push_back(fileDescriptor
);
95 if (server
.send(&request
, sizeof(request
), fds
) != sizeof(request
))
96 UnixError::throwMe(EIO
);
99 secdebug("portserve", "getting reply");
101 if (server
.read(&reply
, sizeof(reply
)) != sizeof(reply
))
102 UnixError::throwMe(EIO
);
104 secdebug("portserve", "server replied %ld", reply
.status
);
105 return ntohl(reply
.status
);
112 // Start the server (fork/exec)
114 static void startServer()
116 const char *serverpath
= PORTSERVERPATH
;
118 if (const char *override
= getenv("PRIVPORTSERVER"))
119 serverpath
= override
;
122 secdebug("portserve", "starting %s", serverpath
);
125 UnixError::throwMe();
127 execl(serverpath
, serverpath
, NULL
);
128 secdebug("portserve", "cannot exec %s (errno=%d)", serverpath
, errno
);
138 // A pure-C interface helper function for overriding bind(2).
139 // This obtains the authorization, then calls AuthorizationBindPrivilegedPort
141 int __authorization_bind(int s
, const struct sockaddr_in
*name
)
143 // obtain authorization
144 AuthorizationItem rights
[] = {
145 { "system.privilege.port.connect", 0, NULL
, 0 }
147 AuthorizationRights rightSet
=
148 { sizeof(rights
) / sizeof(rights
[0]), rights
};
149 AuthorizationRef auth
;
150 if (AuthorizationCreate(&rightSet
, NULL
,
151 kAuthorizationFlagInteractionAllowed
|
152 kAuthorizationFlagExtendRights
|
153 kAuthorizationFlagPreAuthorize
,
160 OSStatus err
= AuthorizationBindPrivilegedPort(s
, name
, auth
, 0);
161 AuthorizationFree(auth
, 0); // ignore errors
164 errno
= (err
>= errSecErrnoBase
&& err
<= errSecErrnoLimit
) ?
165 errno
= err
- errSecErrnoBase
: