]> git.saurik.com Git - apple/security.git/blob - SecurityServer/Authorization/privPortClient.cpp
Security-179.tar.gz
[apple/security.git] / SecurityServer / Authorization / privPortClient.cpp
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 //
20 // privPortClient - Authorization privileged-port binding client side
21 //
22 #include <Security/AuthorizationPriv.h>
23 #include <Security/fdmover.h>
24 #include <Security/debugging.h>
25 #include "privPort.h"
26
27 using namespace UnixPlusPlus;
28 using namespace IPPlusPlus;
29
30
31 //
32 // Where is the trampoline itself?
33 //
34 #if !defined(PORTSERVERPATH)
35 # define PORTSERVERPATH "/System/Library/CoreServices/privportserver" /* fallback */
36 #endif
37
38
39 //
40 // Local functions
41 //
42 static void startServer();
43
44
45 //
46 // The official client function. This does all the work
47 //
48 OSStatus AuthorizationBindPrivilegedPort(int fileDescriptor,
49 const struct sockaddr_in *name,
50 AuthorizationRef authorization,
51 AuthorizationFlags flags)
52 {
53 BEGIN_API
54 unsigned short port = ntohs(name->sin_port);
55 secdebug("portserve", "bind request fd=%d port=%d", fileDescriptor, port);
56
57 // must request a privileged port (don't check for debug version)
58 #if defined(NDEBUG)
59 if (port <= 0 || port >= IPPORT_RESERVED)
60 return errAuthorizationBadAddress;
61 #endif //NEBUG
62
63 // no flags recognized so far
64 if (flags)
65 return errAuthorizationInvalidFlags;
66
67 // form the request message
68 Request request;
69 if (OSStatus err = AuthorizationMakeExternalForm(authorization, &request.authForm))
70 return err;
71 request.requestedName = *name;
72
73 // connect to the port server (start it if we must)
74 UNSockAddress serverAddress(kPrivilegedPortBinder);
75 FdMover server;
76 server.open(AF_UNIX, SOCK_STREAM);
77 try {
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
83 startServer();
84 server.connect(serverAddress);
85 break;
86 default:
87 throw;
88 }
89 }
90
91 // send request
92 secdebug("portserve", "sending request");
93 FdVector fds;
94 fds.push_back(fileDescriptor);
95 if (server.send(&request, sizeof(request), fds) != sizeof(request))
96 UnixError::throwMe(EIO);
97
98 // read reply
99 secdebug("portserve", "getting reply");
100 Reply reply;
101 if (server.read(&reply, sizeof(reply)) != sizeof(reply))
102 UnixError::throwMe(EIO);
103
104 secdebug("portserve", "server replied %ld", reply.status);
105 return ntohl(reply.status);
106
107 END_API(CSSM)
108 }
109
110
111 //
112 // Start the server (fork/exec)
113 //
114 static void startServer()
115 {
116 const char *serverpath = PORTSERVERPATH;
117 #if !defined(NDEBUG)
118 if (const char *override = getenv("PRIVPORTSERVER"))
119 serverpath = override;
120 #endif //!NDEBUG
121
122 secdebug("portserve", "starting %s", serverpath);
123 switch (fork()) {
124 case -1:
125 UnixError::throwMe();
126 case 0: // child
127 execl(serverpath, serverpath, NULL);
128 secdebug("portserve", "cannot exec %s (errno=%d)", serverpath, errno);
129 _exit(1);
130 default: // parent
131 sleep(1);
132 break;
133 }
134 }
135
136
137 //
138 // A pure-C interface helper function for overriding bind(2).
139 // This obtains the authorization, then calls AuthorizationBindPrivilegedPort
140 //
141 int __authorization_bind(int s, const struct sockaddr_in *name)
142 {
143 // obtain authorization
144 AuthorizationItem rights[] = {
145 { "system.privilege.port.connect", 0, NULL, 0 }
146 };
147 AuthorizationRights rightSet =
148 { sizeof(rights) / sizeof(rights[0]), rights };
149 AuthorizationRef auth;
150 if (AuthorizationCreate(&rightSet, NULL,
151 kAuthorizationFlagInteractionAllowed |
152 kAuthorizationFlagExtendRights |
153 kAuthorizationFlagPreAuthorize,
154 &auth)) {
155 errno = EPERM;
156 return -1;
157 }
158
159 // bind
160 OSStatus err = AuthorizationBindPrivilegedPort(s, name, auth, 0);
161 AuthorizationFree(auth, 0); // ignore errors
162
163 if (err) {
164 errno = (err >= errSecErrnoBase && err <= errSecErrnoLimit) ?
165 errno = err - errSecErrnoBase :
166 EPERM;
167 return -1;
168 }
169 return 0;
170 }