source: trunk/Cocoa/Pester/Source/MoreSecurity/MoreUNIX.c@ 118

Last change on this file since 118 was 118, checked in by Nicholas Riley, 21 years ago

Broken, to-be-removed authorization implementation

File size: 11.5 KB
Line 
1/*
2 File: MoreUNIX.c
3
4 Contains: Generic UNIX utilities.
5
6 Written by: Quinn
7
8 Copyright: Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
9
10 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
11 ("Apple") in consideration of your agreement to the following terms, and your
12 use, installation, modification or redistribution of this Apple software
13 constitutes acceptance of these terms. If you do not agree with these terms,
14 please do not use, install, modify or redistribute this Apple software.
15
16 In consideration of your agreement to abide by the following terms, and subject
17 to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
18 copyrights in this original Apple software (the "Apple Software"), to use,
19 reproduce, modify and redistribute the Apple Software, with or without
20 modifications, in source and/or binary forms; provided that if you redistribute
21 the Apple Software in its entirety and without modifications, you must retain
22 this notice and the following text and disclaimers in all such redistributions of
23 the Apple Software. Neither the name, trademarks, service marks or logos of
24 Apple Computer, Inc. may be used to endorse or promote products derived from the
25 Apple Software without specific prior written permission from Apple. Except as
26 expressly stated in this notice, no other rights or licenses, express or implied,
27 are granted by Apple herein, including but not limited to any patent rights that
28 may be infringed by your derivative works or by other works in which the Apple
29 Software may be incorporated.
30
31 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
32 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
33 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
35 COMBINATION WITH YOUR PRODUCTS.
36
37 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
38 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
39 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
41 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
42 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
43 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44
45 Change History (most recent first):
46
47$Log: MoreUNIX.c,v $
48Revision 1.4 2002/12/13 00:30:18 eskimo1
4910.1 compatibility. futimes isn't available in 10.1. Drat! Also, in NSGetExecutablePathOnTenOneAndEarlierOnly, have to skip over multiple NULLs between the environment and the relative path point, in case someone (like MoreSecDestroyInheritedEnvironment perhaps) has called unsetenv.
50
51Revision 1.3 2002/12/12 23:14:29 eskimo1
52C++ compatibility.
53
54Revision 1.2 2002/11/14 20:15:20 eskimo1
55In MoreUNIXCopyFile, correctly set the modified and accessed times of the resulting file.
56
57Revision 1.1 2002/11/09 00:15:21 eskimo1
58A collection of useful UNIX-level routines.
59
60
61*/
62
63/////////////////////////////////////////////////////////////////
64
65// Our prototypes
66
67#include "MoreUNIX.h"
68
69// System interfaces
70
71#include <sys/param.h>
72#include <mach-o/dyld.h>
73#include <stdio.h>
74#include <string.h>
75#include <assert.h>
76#include <stdlib.h>
77#include <errno.h>
78#include <unistd.h>
79#include <signal.h>
80#include <fcntl.h>
81#include <sys/stat.h>
82#include <stdbool.h>
83
84// "crt_externs.h" has no C++ guards [3126393], so we have to provide them
85// ourself otherwise we get a link error.
86
87#ifdef __cplusplus
88extern "C" {
89#endif
90
91#include <crt_externs.h>
92
93#ifdef __cplusplus
94}
95#endif
96
97// MIB Interfaces
98
99/////////////////////////////////////////////////////////////////
100
101#if MORE_DEBUG
102
103 // There's a macro version of this in the header.
104
105 extern int MoreUNIXErrno(int result)
106 {
107 int err;
108
109 err = 0;
110 if (result < 0) {
111 err = errno;
112 assert(err != 0);
113 }
114 return err;
115 }
116
117#endif
118
119/////////////////////////////////////////////////////////////////
120
121static int NSGetExecutablePathOnTenOneAndEarlierOnly(char *execPath, size_t *execPathSize)
122{
123 int err = 0;
124 char **cursor;
125 char *possiblyRelativePath;
126 char absolutePath[MAXPATHLEN];
127 size_t absolutePathSize;
128
129 assert(execPath != NULL);
130 assert(execPathSize != NULL);
131
132 cursor = (char **) (*(_NSGetArgv()) + *(_NSGetArgc()));
133
134 // There should be a NULL after the argv array.
135 // If not, error out.
136
137 if (*cursor != 0) {
138 err = -1;
139 }
140
141 if (err == 0) {
142 // Skip past the NULL after the argv array.
143
144 cursor += 1;
145
146 // Now, skip over the entire kernel-supplied environment,
147 // which is an array of char * terminated by a NULL.
148
149 while (*cursor != 0) {
150 cursor += 1;
151 }
152
153 // Skip over the NULL terminating the environment. Actually,
154 // there can be multiple NULLs if the program has called
155 // unsetenv, so we skip along until we find a the next non-NULL.
156
157 while (*cursor == 0) {
158 cursor += 1;
159 }
160
161 // Now we have the path that was passed to exec
162 // (not the argv[0] path, but the path that the kernel
163 // actually executed).
164
165 possiblyRelativePath = *cursor;
166
167 // Convert the possibly relative path to an absolute
168 // path. We use realpath for expedience, although
169 // the real implementation of _NSGetExecutablePath
170 // uses getcwd and can return a path with symbolic links
171 // etc in it.
172
173 if (realpath(possiblyRelativePath, absolutePath) == NULL) {
174 err = errno;
175 }
176 }
177
178 // Now copy the path out into the client's buffer, returning
179 // an error if the buffer isn't big enough.
180
181 if (err == 0) {
182 absolutePathSize = (strlen(absolutePath) + 1);
183
184 if (absolutePathSize <= *execPathSize) {
185 strcpy(execPath, absolutePath);
186 } else {
187 err = -1;
188 }
189
190 *execPathSize = absolutePathSize;
191 }
192
193 return err;
194}
195
196typedef int (*NSGetExecutablePathProcPtr)(char *buf, size_t *bufsize);
197
198extern int MoreGetExecutablePath(char *execPath, size_t *execPathSize)
199{
200 if (NSIsSymbolNameDefined("__NSGetExecutablePath")) {
201 return ((NSGetExecutablePathProcPtr) NSAddressOfSymbol(NSLookupAndBindSymbol("__NSGetExecutablePath")))(execPath, execPathSize);
202 } else {
203 // The function _NSGetExecutablePath() is new in Mac OS X 10.2,
204 // so use this custom version when running on 10.1.x and earlier.
205 return NSGetExecutablePathOnTenOneAndEarlierOnly(execPath, execPathSize);
206 }
207}
208
209/////////////////////////////////////////////////////////////////
210
211extern int MoreUNIXRead( int fd, void *buf, size_t bufSize, size_t *bytesRead )
212 // See comment in header.
213{
214 int err;
215 char * cursor;
216 size_t bytesLeft;
217 ssize_t bytesThisTime;
218
219 assert(fd >= 0);
220 assert(buf != NULL);
221
222 err = 0;
223 bytesLeft = bufSize;
224 cursor = (char *) buf;
225 while ( (err == 0) && (bytesLeft != 0) ) {
226 bytesThisTime = read(fd, cursor, bytesLeft);
227 if (bytesThisTime > 0) {
228 cursor += bytesThisTime;
229 bytesLeft -= bytesThisTime;
230 } else if (bytesThisTime == 0) {
231 err = EPIPE;
232 } else {
233 assert(bytesThisTime == -1);
234
235 err = errno;
236 assert(err != 0);
237 if (err == EINTR) {
238 err = 0; // let's loop again
239 }
240 }
241 }
242 if (bytesRead != NULL) {
243 *bytesRead = bufSize - bytesLeft;
244 }
245
246 return err;
247}
248
249extern int MoreUNIXWrite(int fd, const void *buf, size_t bufSize, size_t *bytesWritten)
250 // See comment in header.
251{
252 int err;
253 char * cursor;
254 size_t bytesLeft;
255 ssize_t bytesThisTime;
256
257 assert(fd >= 0);
258 assert(buf != NULL);
259
260 // SIGPIPE occurs when you write to pipe or socket
261 // whose other end has been closed. The default action
262 // for SIGPIPE is to terminate the process. That's
263 // probably not what you wanted. So, in the debug build,
264 // we check that you've set the signal action to SIG_IGN
265 // (ignore). Of course, you could be building a program
266 // that needs SIGPIPE to work in some special way, in
267 // which case you should define MORE_UNIX_WRITE_CHECK_SIGPIPE
268 // to 0 to bypass this check.
269 //
270 // MoreUNIXIgnoreSIGPIPE, a helper routine defined below,
271 // lets you disable SIGPIPE easily.
272
273 #if !defined(MORE_UNIX_WRITE_CHECK_SIGPIPE)
274 #define MORE_UNIX_WRITE_CHECK_SIGPIPE 1
275 #endif
276 #if MORE_DEBUG && MORE_UNIX_WRITE_CHECK_SIGPIPE
277 {
278 int junk;
279 struct sigaction currentSignalState;
280
281 junk = sigaction(SIGPIPE, NULL, &currentSignalState);
282 assert(junk == 0);
283
284 assert( currentSignalState.sa_handler == SIG_IGN );
285 }
286 #endif
287
288 err = 0;
289 bytesLeft = bufSize;
290 cursor = (char *) buf;
291 while ( (err == 0) && (bytesLeft != 0) ) {
292 bytesThisTime = write(fd, cursor, bytesLeft);
293 if (bytesThisTime > 0) {
294 cursor += bytesThisTime;
295 bytesLeft -= bytesThisTime;
296 } else if (bytesThisTime == 0) {
297 assert(false);
298 err = EPIPE;
299 } else {
300 assert(bytesThisTime == -1);
301
302 err = errno;
303 assert(err != 0);
304 if (err == EINTR) {
305 err = 0; // let's loop again
306 }
307 }
308 }
309 if (bytesWritten != NULL) {
310 *bytesWritten = bufSize - bytesLeft;
311 }
312
313 return err;
314}
315
316extern int MoreUNIXIgnoreSIGPIPE(void)
317 // See comment in header.
318{
319 int err;
320 struct sigaction signalState;
321
322 err = sigaction(SIGPIPE, NULL, &signalState);
323 err = MoreUNIXErrno(err);
324 if (err == 0) {
325 signalState.sa_handler = SIG_IGN;
326
327 err = sigaction(SIGPIPE, &signalState, NULL);
328 err = MoreUNIXErrno(err);
329 }
330
331 return err;
332}
333
334extern int MoreUNIXCopyDescriptorToDescriptor(int source, int dest)
335 // See comment in header.
336{
337 int err;
338 bool done;
339 char * buffer;
340 static const size_t kBufferSize = 64 * 1024;
341
342 assert(source >= 0);
343 assert(dest >= 0);
344
345 err = 0;
346 buffer = (char *) malloc(kBufferSize);
347 if (buffer == NULL) {
348 err = ENOMEM;
349 }
350
351 if (err == 0) {
352 done = false;
353 do {
354 size_t bytesRead;
355
356 err = MoreUNIXRead(source, buffer, kBufferSize, &bytesRead);
357 if (err == EPIPE) {
358 done = true;
359 err = 0;
360 }
361 if (err == 0) {
362 err = MoreUNIXWrite(dest, buffer, bytesRead, NULL);
363 }
364 } while (err == 0 && !done);
365 }
366
367 free(buffer);
368
369 return err;
370}
371
372extern int MoreUNIXCopyFile(const char *source, const char *dest)
373 // See comment in header.
374{
375 int err;
376 int junk;
377 int sourceFD;
378 int destFD;
379 struct stat sb;
380
381 assert(source != NULL);
382 assert(dest != NULL);
383
384 sourceFD = -1;
385 destFD = -1;
386
387 err = stat(source, &sb);
388 err = MoreUNIXErrno(err);
389
390 if (err == 0) {
391 sourceFD = open(source, O_RDONLY, 0);
392 err = MoreUNIXErrno(sourceFD);
393 }
394
395 if (err == 0) {
396 destFD = open(dest, O_WRONLY | O_CREAT | O_TRUNC, sb.st_mode & ~(S_ISUID | S_ISGID | S_ISVTX));
397 err = MoreUNIXErrno(destFD);
398 }
399
400 if (err == 0) {
401 err = MoreUNIXCopyDescriptorToDescriptor(sourceFD, destFD);
402 }
403
404 // Close the descriptors.
405
406 if (sourceFD != -1) {
407 junk = close(sourceFD);
408 assert(junk == 0);
409 }
410 if (destFD != -1) {
411 junk = close(destFD);
412 assert(junk == 0);
413 }
414
415 // Set the access and modification times of the destination
416 // to match the source. I originally did this using futimes,
417 // but hey, that's not available on 10.1, so now I do it
418 // using utimes. *sigh*
419
420 if (err == 0) {
421 struct timeval times[2];
422
423 TIMESPEC_TO_TIMEVAL(&times[0], &sb.st_atimespec);
424 TIMESPEC_TO_TIMEVAL(&times[1], &sb.st_mtimespec);
425
426 err = utimes(dest, times);
427 err = MoreUNIXErrno(err);
428 }
429
430 return err;
431}
Note: See TracBrowser for help on using the repository browser.