From aa59983ad5a41ca0272b5584ad9dabbde5b0c49b Mon Sep 17 00:00:00 2001 From: Apple Date: Mon, 20 Feb 2006 21:41:55 +0000 Subject: [PATCH] launchd-106.10.tar.gz --- launchd/src/ConsoleMessage.c | 2 +- launchd/src/IPC.c | 6 +- launchd/src/StartupItems.c | 2 +- launchd/src/bootstrap.c | 30 +- launchd/src/launch.h | 1 + launchd/src/launchctl.c | 327 +++++++++++++----- launchd/src/launchd.c | 48 ++- launchd/src/launchd.plist.5 | 2 + launchd/src/launchdebugd.c | 26 +- launchd/src/launchproxy.c | 4 + launchd/src/liblaunch.c | 196 +++++++++-- launchd/src/lists.c | 13 +- launchd/src/rc | 5 +- launchd/src/register_mach_bootstrap_servers.c | 2 +- launchd/src/wait4path.c | 3 + 15 files changed, 503 insertions(+), 164 deletions(-) diff --git a/launchd/src/ConsoleMessage.c b/launchd/src/ConsoleMessage.c index a07f4ab..30f1cf6 100644 --- a/launchd/src/ConsoleMessage.c +++ b/launchd/src/ConsoleMessage.c @@ -235,7 +235,7 @@ static void replyCallback(CFMachPortRef port __attribute__((unused)), void * if (aReply != NULL && aMessage->aProtocol == kIPCProtocolVersion && aMessage->aByteLength >= 0) { - *aReply = CFDataCreate(NULL, (char *) aMessage + aMessage->aByteLength, aMessage->aByteLength); + *aReply = CFDataCreate(NULL, (UInt8 *) aMessage + aMessage->aByteLength, aMessage->aByteLength); } else if (aReply != NULL) { *aReply = NULL; } diff --git a/launchd/src/IPC.c b/launchd/src/IPC.c index b8e4dd6..6c8e2aa 100644 --- a/launchd/src/IPC.c +++ b/launchd/src/IPC.c @@ -238,7 +238,7 @@ queryConfigSetting(StartupContext aStartupContext, CFDictionaryRef anIPCMessage) } } } - return CFDataCreate(NULL, aValue, strlen(aValue) + 1); /* aValue + null */ + return CFDataCreate(NULL, (const UInt8 *)aValue, strlen(aValue) + 1); /* aValue + null */ } static void *handleIPCMessage(void *aMsgParam, CFIndex aMessageSize __attribute__((unused)), CFAllocatorRef anAllocator __attribute__((unused)), void *aMachPort) { @@ -313,7 +313,7 @@ static void *handleIPCMessage(void *aMsgParam, CFIndex aMessageSize __attribu * Generate a Mach message for the result data. */ if (!aResult) - aResult = CFDataCreateWithBytesNoCopy(NULL, "", 1, kCFAllocatorNull); + aResult = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)"", 1, kCFAllocatorNull); if (aResult) { CFIndex aDataSize = CFDataGetLength(aResult); CFIndex aReplyMessageSize = round_msg(sizeof(SystemStarterIPCMessage) + aDataSize + 3); @@ -365,7 +365,7 @@ CreateIPCRunLoopSource(CFStringRef aPortName, StartupContext aStartupContext) if (aMachPort && aPortName) { CFIndex aPortNameLength = CFStringGetLength(aPortName); CFIndex aPortNameSize = CFStringGetMaximumSizeForEncoding(aPortNameLength, kCFStringEncodingUTF8) + 1; - uint8_t *aBuffer = CFAllocatorAllocate(NULL, aPortNameSize, 0); + char *aBuffer = CFAllocatorAllocate(NULL, aPortNameSize, 0); if (aBuffer && CFStringGetCString(aPortName, aBuffer, aPortNameSize, diff --git a/launchd/src/StartupItems.c b/launchd/src/StartupItems.c index 615cf60..3c95129 100644 --- a/launchd/src/StartupItems.c +++ b/launchd/src/StartupItems.c @@ -356,7 +356,7 @@ StartupItemListCreateWithMask(NSSearchPathDomainMask aMask) aConfigData = CFDataCreateWithBytesNoCopy(NULL, - aConfigFileContentsBuffer, + (const UInt8 *)aConfigFileContentsBuffer, aConfigFileContentsSize, kCFAllocatorNull); diff --git a/launchd/src/bootstrap.c b/launchd/src/bootstrap.c index e309a31..82ef86a 100644 --- a/launchd/src/bootstrap.c +++ b/launchd/src/bootstrap.c @@ -621,11 +621,37 @@ exec_server(server_t *serverp) serverp->cmd); } - if (serverp->uid != inherited_uid) - if (setuid(serverp->uid) < 0) + if (serverp->uid != inherited_uid) { + struct passwd *pwd = getpwuid(serverp->uid); + gid_t g; + + if (NULL == pwd) { + panic("Disabled server %x bootstrap %x: \"%s\": getpwuid(%d) failed", + serverp->port, serverp->bootstrap->bootstrap_port, + serverp->cmd, serverp->uid); + } + + g = pwd->pw_gid; + + if (-1 == setgroups(1, &g)) { + panic("Disabled server %x bootstrap %x: \"%s\": setgroups(1, %d): %s", + serverp->port, serverp->bootstrap->bootstrap_port, + serverp->cmd, g, strerror(errno)); + } + + if (-1 == setgid(g)) { + panic("Disabled server %x bootstrap %x: \"%s\": setgid(%d): %s", + serverp->port, serverp->bootstrap->bootstrap_port, + serverp->cmd, g, strerror(errno)); + } + + if (-1 == setuid(serverp->uid)) { panic("Disabled server %x bootstrap %x: \"%s\": setuid(%d): %s", serverp->port, serverp->bootstrap->bootstrap_port, serverp->cmd, serverp->uid, strerror(errno)); + } + } + if (setsid() < 0) { /* diff --git a/launchd/src/launch.h b/launchd/src/launch.h index 0a8a175..1d93ad9 100644 --- a/launchd/src/launch.h +++ b/launchd/src/launch.h @@ -94,6 +94,7 @@ #define LAUNCH_JOBSOCKETKEY_BONJOUR "Bonjour" #define LAUNCH_JOBSOCKETKEY_SECUREWITHKEY "SecureSocketWithKey" #define LAUNCH_JOBSOCKETKEY_PATHNAME "SockPathName" +#define LAUNCH_JOBSOCKETKEY_PATHMODE "SockPathMode" #define LAUNCH_JOBSOCKETKEY_NODENAME "SockNodeName" #define LAUNCH_JOBSOCKETKEY_SERVICENAME "SockServiceName" #define LAUNCH_JOBSOCKETKEY_FAMILY "SockFamily" diff --git a/launchd/src/launchctl.c b/launchd/src/launchctl.c index 5142250..a0a405c 100644 --- a/launchd/src/launchctl.c +++ b/launchd/src/launchctl.c @@ -21,6 +21,8 @@ * @APPLE_LICENSE_HEADER_END@ */ #include +#include +#include #include #include #include @@ -50,7 +52,15 @@ #define LAUNCH_SECDIR "/tmp/launch-XXXXXX" +#define MACHINIT_JOBKEY_ONDEMAND "OnDemand" +#define MACHINIT_JOBKEY_SERVICENAME "ServiceName" +#define MACHINIT_JOBKEY_COMMAND "Command" +#define MACHINIT_JOBKEY_ISKUNCSERVER "isKUNCServer" + + +static void myCFDictionaryApplyFunction(const void *key, const void *value, void *context); static bool launch_data_array_append(launch_data_t a, launch_data_t o); +static void distill_jobs(launch_data_t); static void distill_config_file(launch_data_t); static void sock_dict_cb(launch_data_t what, const char *key, void *context); static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data_t fdarray, launch_data_t thejob); @@ -58,12 +68,19 @@ static launch_data_t CF2launch_data(CFTypeRef); static launch_data_t read_plist_file(const char *file, bool editondisk, bool load); static CFPropertyListRef CreateMyPropertyListFromFile(const char *); static void WriteMyPropertyListToFile(CFPropertyListRef, const char *); -static void readpath(const char *, launch_data_t, launch_data_t, bool editondisk, bool load, bool forceload); +static void readpath(const char *, launch_data_t, launch_data_t, launch_data_t, bool editondisk, bool load, bool forceload); +static void readfile(const char *, launch_data_t, launch_data_t, launch_data_t, bool editondisk, bool load, bool forceload); static int _fd(int); static int demux_cmd(int argc, char *const argv[]); static launch_data_t do_rendezvous_magic(const struct addrinfo *res, const char *serv); static void submit_job_pass(launch_data_t jobs); +static void submit_mach_jobs(launch_data_t jobs); +static void let_go_of_mach_jobs(void); static void do_mgroup_join(int fd, int family, int socktype, int protocol, const char *mgroup); +static void print_jobs(launch_data_t j, const char *label, void *context); +static bool is_legacy_mach_job(launch_data_t obj); +static bool delay_to_second_pass(launch_data_t o); +static void delay_to_second_pass2(launch_data_t o, const char *key, void *context); static int load_and_unload_cmd(int argc, char *const argv[]); //static int reload_cmd(int argc, char *const argv[]); @@ -216,21 +233,29 @@ static int setenv_cmd(int argc, char *const argv[]) return 0; } +static void print_launchd_env(launch_data_t obj, const char *key, void *context) +{ + bool *is_csh = context; + + if (*is_csh) + fprintf(stdout, "setenv %s %s;\n", key, launch_data_get_string(obj)); + else + fprintf(stdout, "%s=%s; export %s;\n", key, launch_data_get_string(obj), key); +} + +static void print_key_value(launch_data_t obj, const char *key, void *context) +{ + const char *k = context; + + if (!strcmp(key, k)) + fprintf(stdout, "%s\n", launch_data_get_string(obj)); +} + static int getenv_and_export_cmd(int argc, char *const argv[] __attribute__((unused))) { launch_data_t resp, msg; bool is_csh = false; - const char *k; - void print_launchd_env(launch_data_t obj, const char *key, void *context __attribute__((unused))) { - if (is_csh) - fprintf(stdout, "setenv %s %s;\n", key, launch_data_get_string(obj)); - else - fprintf(stdout, "%s=%s; export %s;\n", key, launch_data_get_string(obj), key); - } - void print_key_value(launch_data_t obj, const char *key, void *context __attribute__((unused))) { - if (!strcmp(key, k)) - fprintf(stdout, "%s\n", launch_data_get_string(obj)); - } + char *k; if (!strcmp(argv[0], "export")) { char *s = getenv("SHELL"); @@ -249,7 +274,10 @@ static int getenv_and_export_cmd(int argc, char *const argv[] __attribute__((unu launch_data_free(msg); if (resp) { - launch_data_dict_iterate(resp, (!strcmp(argv[0], "export")) ? print_launchd_env : print_key_value, NULL); + if (!strcmp(argv[0], "export")) + launch_data_dict_iterate(resp, print_launchd_env, &is_csh); + else + launch_data_dict_iterate(resp, print_key_value, k); launch_data_free(resp); } else { fprintf(stderr, "launch_msg(\"" LAUNCH_KEY_GETUSERENVIRONMENT "\"): %s\n", strerror(errno)); @@ -286,7 +314,8 @@ static void unloadjob(launch_data_t job) launch_data_free(resp); } -static launch_data_t read_plist_file(const char *file, bool editondisk, bool load) +launch_data_t +read_plist_file(const char *file, bool editondisk, bool load) { CFPropertyListRef plist = CreateMyPropertyListFromFile(file); launch_data_t r = NULL; @@ -311,7 +340,8 @@ static launch_data_t read_plist_file(const char *file, bool editondisk, bool loa return r; } -static void delay_to_second_pass2(launch_data_t o, const char *key, void *context) +void +delay_to_second_pass2(launch_data_t o, const char *key, void *context) { bool *res = context; size_t i; @@ -334,7 +364,8 @@ static void delay_to_second_pass2(launch_data_t o, const char *key, void *contex } } -static bool delay_to_second_pass(launch_data_t o) +bool +delay_to_second_pass(launch_data_t o) { bool res = false; @@ -348,7 +379,8 @@ static bool delay_to_second_pass(launch_data_t o) return res; } -static void readfile(const char *what, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load, bool forceload) +void +readfile(const char *what, launch_data_t pass0, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load, bool forceload) { launch_data_t tmpd, thejob; bool job_disabled = false; @@ -358,6 +390,11 @@ static void readfile(const char *what, launch_data_t pass1, launch_data_t pass2, return; } + if (is_legacy_mach_job(thejob)) { + launch_data_array_append(pass0, thejob); + return; + } + if (NULL == launch_data_dict_lookup(thejob, LAUNCH_JOBKEY_LABEL)) { fprintf(stderr, "%s: missing the Label key: %s\n", getprogname(), what); launch_data_free(thejob); @@ -381,7 +418,8 @@ static void readfile(const char *what, launch_data_t pass1, launch_data_t pass2, launch_data_array_append(pass1, thejob); } -static void readpath(const char *what, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load, bool forceload) +void +readpath(const char *what, launch_data_t pass0, launch_data_t pass1, launch_data_t pass2, bool editondisk, bool load, bool forceload) { char buf[MAXPATHLEN]; struct stat sb; @@ -392,7 +430,7 @@ static void readpath(const char *what, launch_data_t pass1, launch_data_t pass2, return; if (S_ISREG(sb.st_mode) && !(sb.st_mode & S_IWOTH)) { - readfile(what, pass1, pass2, editondisk, load, forceload); + readfile(what, pass0, pass1, pass2, editondisk, load, forceload); } else { if ((d = opendir(what)) == NULL) { fprintf(stderr, "%s: opendir() failed to open the directory\n", getprogname()); @@ -404,7 +442,7 @@ static void readpath(const char *what, launch_data_t pass1, launch_data_t pass2, continue; snprintf(buf, sizeof(buf), "%s/%s", what, de->d_name); - readfile(buf, pass1, pass2, editondisk, load, forceload); + readfile(buf, pass0, pass1, pass2, editondisk, load, forceload); } closedir(d); } @@ -415,7 +453,17 @@ struct distill_context { launch_data_t newsockdict; }; -static void distill_config_file(launch_data_t id_plist) +void +distill_jobs(launch_data_t jobs) +{ + size_t i, c = launch_data_array_get_count(jobs); + + for (i = 0; i < c; i++) + distill_config_file(launch_data_array_get_index(jobs, i)); +} + +void +distill_config_file(launch_data_t id_plist) { struct distill_context dc = { id_plist, NULL }; launch_data_t tmp; @@ -487,6 +535,9 @@ static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_PATHNAME))) { struct sockaddr_un sun; + mode_t sun_mode = 0; + mode_t oldmask; + bool setm = false; memset(&sun, 0, sizeof(sun)); @@ -497,15 +548,26 @@ static void sock_dict_edit_entry(launch_data_t tmp, const char *key, launch_data if ((sfd = _fd(socket(AF_UNIX, st, 0))) == -1) return; + if ((val = launch_data_dict_lookup(tmp, LAUNCH_JOBSOCKETKEY_PATHMODE))) { + sun_mode = (mode_t)launch_data_get_integer(val); + setm = true; + } + if (passive) { if (unlink(sun.sun_path) == -1 && errno != ENOENT) { close(sfd); return; } + oldmask = umask(S_IRWXG|S_IRWXO); if (bind(sfd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { close(sfd); + umask(oldmask); return; } + umask(oldmask); + if (setm) { + chmod(sun.sun_path, sun_mode); + } if ((st == SOCK_STREAM || st == SOCK_SEQPACKET) && listen(sfd, SOMAXCONN) == -1) { close(sfd); @@ -732,7 +794,7 @@ static CFPropertyListRef CreateMyPropertyListFromFile(const char *posixfile) SInt32 errorCode; CFURLRef fileURL; - fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, posixfile, strlen(posixfile), false); + fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false); if (!fileURL) fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) @@ -750,7 +812,7 @@ static void WriteMyPropertyListToFile(CFPropertyListRef plist, const char *posix CFURLRef fileURL; SInt32 errorCode; - fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, posixfile, strlen(posixfile), false); + fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false); if (!fileURL) fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); resourceData = CFPropertyListCreateXMLData(kCFAllocatorDefault, plist); @@ -866,7 +928,7 @@ static int _fd(int fd) static int load_and_unload_cmd(int argc, char *const argv[]) { - launch_data_t pass1, pass2; + launch_data_t pass0, pass1, pass2; int i, ch; bool wflag = false; bool lflag = false; @@ -892,7 +954,8 @@ static int load_and_unload_cmd(int argc, char *const argv[]) return 1; } - /* I wish I didn't need to do two passes, but I need to load mDNSResponder and use it too. + /* I wish I didn't need to do three passes, but I need to load mDNSResponder and use it too. + * And loading legacy mach init jobs is extra fun. * * In later versions of launchd, I hope to load everything in the first pass, * then do the Bonjour magic on the jobs that need it, and reload them, but for now, @@ -900,26 +963,30 @@ static int load_and_unload_cmd(int argc, char *const argv[]) * launchd doesn't have reload support right now. */ + pass0 = launch_data_alloc(LAUNCH_DATA_ARRAY); pass1 = launch_data_alloc(LAUNCH_DATA_ARRAY); pass2 = launch_data_alloc(LAUNCH_DATA_ARRAY); for (i = 0; i < argc; i++) - readpath(argv[i], pass1, pass2, wflag, lflag, Fflag); + readpath(argv[i], pass0, pass1, pass2, wflag, lflag, Fflag); - if (0 == launch_data_array_get_count(pass1) && 0 == launch_data_array_get_count(pass2)) { + if (launch_data_array_get_count(pass0) == 0 && + launch_data_array_get_count(pass1) == 0 && + launch_data_array_get_count(pass2) == 0) { fprintf(stderr, "nothing found to %s\n", lflag ? "load" : "unload"); + launch_data_free(pass0); launch_data_free(pass1); launch_data_free(pass2); return 1; } if (lflag) { - if (0 < launch_data_array_get_count(pass1)) { - submit_job_pass(pass1); - } - if (0 < launch_data_array_get_count(pass2)) { - submit_job_pass(pass2); - } + distill_jobs(pass1); + submit_mach_jobs(pass0); + submit_job_pass(pass1); + let_go_of_mach_jobs(); + distill_jobs(pass2); + submit_job_pass(pass2); } else { for (i = 0; i < (int)launch_data_array_get_count(pass1); i++) unloadjob(launch_data_array_get_index(pass1, i)); @@ -930,14 +997,74 @@ static int load_and_unload_cmd(int argc, char *const argv[]) return 0; } -static void submit_job_pass(launch_data_t jobs) +static mach_port_t *msrvs = NULL; +static size_t msrvs_cnt = 0; + +void +submit_mach_jobs(launch_data_t jobs) +{ + size_t i, c; + + c = launch_data_array_get_count(jobs); + + msrvs = calloc(1, sizeof(mach_port_t) * c); + msrvs_cnt = c; + + for (i = 0; i < c; i++) { + launch_data_t tmp, oai = launch_data_array_get_index(jobs, i); + const char *sn = NULL, *cmd = NULL; + bool d = true, k = false; + mach_port_t msr, msv, mhp; + kern_return_t kr; + uid_t u = getuid(); + + if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_ONDEMAND))) + d = launch_data_get_bool(tmp); + if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_ISKUNCSERVER))) + k = launch_data_get_bool(tmp); + if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_SERVICENAME))) + sn = launch_data_get_string(tmp); + if ((tmp = launch_data_dict_lookup(oai, MACHINIT_JOBKEY_COMMAND))) + cmd = launch_data_get_string(tmp); + + if ((kr = bootstrap_create_server(bootstrap_port, (char *)cmd, u, d, &msr)) != KERN_SUCCESS) { + fprintf(stderr, "%s: bootstrap_create_server(): %d\n", getprogname(), kr); + continue; + } + if ((kr = bootstrap_create_service(msr, (char*)sn, &msv)) != KERN_SUCCESS) { + fprintf(stderr, "%s: bootstrap_create_service(): %d\n", getprogname(), kr); + mach_port_destroy(mach_task_self(), msr); + continue; + } + if (k) { + mhp = mach_host_self(); + if ((kr = host_set_UNDServer(mhp, msv)) != KERN_SUCCESS) + fprintf(stderr, "%s: host_set_UNDServer(): %s\n", getprogname(), mach_error_string(kr)); + mach_port_deallocate(mach_task_self(), mhp); + } + mach_port_deallocate(mach_task_self(), msv); + msrvs[i] = msr; + } +} + +void +let_go_of_mach_jobs(void) +{ + size_t i; + + for (i = 0; i < msrvs_cnt; i++) + mach_port_destroy(mach_task_self(), msrvs[i]); +} + +void +submit_job_pass(launch_data_t jobs) { launch_data_t msg, resp; size_t i; int e; - for (i = 0; i < launch_data_array_get_count(jobs); i++) - distill_config_file(launch_data_array_get_index(jobs, i)); + if (launch_data_array_get_count(jobs) == 0) + return; msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY); @@ -1262,6 +1389,68 @@ static int logupdate_cmd(int argc, char *const argv[]) return r; } +static const struct { + const char *name; + int lim; +} limlookup[] = { + { "cpu", RLIMIT_CPU }, + { "filesize", RLIMIT_FSIZE }, + { "data", RLIMIT_DATA }, + { "stack", RLIMIT_STACK }, + { "core", RLIMIT_CORE }, + { "rss", RLIMIT_RSS }, + { "memlock", RLIMIT_MEMLOCK }, + { "maxproc", RLIMIT_NPROC }, + { "maxfiles", RLIMIT_NOFILE } +}; + +static const size_t limlookupcnt = sizeof limlookup / sizeof limlookup[0]; + +static ssize_t name2num(const char *n) +{ + size_t i; + + for (i = 0; i < limlookupcnt; i++) { + if (!strcmp(limlookup[i].name, n)) { + return limlookup[i].lim; + } + } + return -1; +} + +static const char *num2name(int n) +{ + size_t i; + + for (i = 0; i < limlookupcnt; i++) { + if (limlookup[i].lim == n) + return limlookup[i].name; + } + return NULL; +} + +static const char *lim2str(rlim_t val, char *buf) +{ + if (val == RLIM_INFINITY) + strcpy(buf, "unlimited"); + else + sprintf(buf, "%lld", val); + return buf; +} + +static bool str2lim(const char *buf, rlim_t *res) +{ + char *endptr; + *res = strtoll(buf, &endptr, 10); + if (!strcmp(buf, "unlimited")) { + *res = RLIM_INFINITY; + return false; + } else if (*endptr == '\0') { + return false; + } + return true; +} + static int limit_cmd(int argc __attribute__((unused)), char *const argv[]) { char slimstr[100]; @@ -1269,58 +1458,10 @@ static int limit_cmd(int argc __attribute__((unused)), char *const argv[]) struct rlimit *lmts = NULL; launch_data_t resp, resp1 = NULL, msg, tmp; int r = 0; - size_t i, lsz = -1, which = 0; + size_t i, lsz = -1; + ssize_t which = 0; rlim_t slim = -1, hlim = -1; bool badargs = false; - static const struct { - const char *name; - int lim; - } limlookup[] = { - { "cpu", RLIMIT_CPU }, - { "filesize", RLIMIT_FSIZE }, - { "data", RLIMIT_DATA }, - { "stack", RLIMIT_STACK }, - { "core", RLIMIT_CORE }, - { "rss", RLIMIT_RSS }, - { "memlock", RLIMIT_MEMLOCK }, - { "maxproc", RLIMIT_NPROC }, - { "maxfiles", RLIMIT_NOFILE } - }; - size_t limlookupcnt = sizeof limlookup / sizeof limlookup[0]; - bool name2num(const char *n) { - for (i = 0; i < limlookupcnt; i++) { - if (!strcmp(limlookup[i].name, n)) { - which = limlookup[i].lim; - return false; - } - } - return true; - }; - const char *num2name(int n) { - for (i = 0; i < limlookupcnt; i++) { - if (limlookup[i].lim == n) - return limlookup[i].name; - } - return NULL; - }; - const char *lim2str(rlim_t val, char *buf) { - if (val == RLIM_INFINITY) - strcpy(buf, "unlimited"); - else - sprintf(buf, "%lld", val); - return buf; - }; - bool str2lim(const char *buf, rlim_t *res) { - char *endptr; - *res = strtoll(buf, &endptr, 10); - if (!strcmp(buf, "unlimited")) { - *res = RLIM_INFINITY; - return false; - } else if (*endptr == '\0') { - return false; - } - return true; - }; if (argc > 4) badargs = true; @@ -1333,7 +1474,7 @@ static int limit_cmd(int argc __attribute__((unused)), char *const argv[]) if (argc == 4 && str2lim(argv[3], &hlim)) badargs = true; - if (argc >= 2 && name2num(argv[1])) + if (argc >= 2 && -1 == (which = name2num(argv[1]))) badargs = true; if (badargs) { @@ -1356,7 +1497,7 @@ static int limit_cmd(int argc __attribute__((unused)), char *const argv[]) lsz = launch_data_get_opaque_size(resp); if (argc <= 2) { for (i = 0; i < (lsz / sizeof(struct rlimit)); i++) { - if (argc == 2 && which != i) + if (argc == 2 && (size_t)which != i) continue; fprintf(stdout, "\t%-12s%-15s%-15s\n", num2name(i), lim2str(lmts[i].rlim_cur, slimstr), @@ -1518,3 +1659,13 @@ static bool launch_data_array_append(launch_data_t a, launch_data_t o) return launch_data_array_set_index(a, o, offt); } + +bool +is_legacy_mach_job(launch_data_t obj) +{ + bool has_servicename = launch_data_dict_lookup(obj, MACHINIT_JOBKEY_SERVICENAME); + bool has_command = launch_data_dict_lookup(obj, MACHINIT_JOBKEY_COMMAND); + bool has_label = launch_data_dict_lookup(obj, LAUNCH_JOBKEY_LABEL); + + return has_command && has_servicename && !has_label; +} diff --git a/launchd/src/launchd.c b/launchd/src/launchd.c index 0eb441b..d6c1057 100644 --- a/launchd/src/launchd.c +++ b/launchd/src/launchd.c @@ -171,6 +171,7 @@ static void loopback_setup(void); static void workaround3048875(int argc, char *argv[]); static void reload_launchd_config(void); static int dir_has_files(const char *path); +static void testfd_or_openfd(int fd, const char *path, int flags); static void setup_job_env(launch_data_t obj, const char *key, void *context); static void unsetup_job_env(launch_data_t obj, const char *key, void *context); @@ -192,20 +193,6 @@ int main(int argc, char *argv[]) SIGTERM, SIGURG, SIGTSTP, SIGTSTP, SIGCONT, /*SIGCHLD,*/ SIGTTIN, SIGTTOU, SIGIO, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGINFO, SIGUSR1, SIGUSR2 }; - void testfd_or_openfd(int fd, const char *path, int flags) { - int tmpfd; - - if (-1 != (tmpfd = dup(fd))) { - close(tmpfd); - } else { - if (-1 == (tmpfd = open(path, flags))) { - syslog(LOG_ERR, "open(\"%s\", ...): %m", path); - } else if (tmpfd != fd) { - dup2(tmpfd, fd); - close(tmpfd); - } - } - }; struct kevent kev; size_t i; bool sflag = false, xflag = false, vflag = false, dflag = false; @@ -333,11 +320,26 @@ static void pid1_magic_init(bool sflag, bool vflag, bool xflag) int memmib[2] = { CTL_HW, HW_PHYSMEM }; int mvnmib[2] = { CTL_KERN, KERN_MAXVNODES }; int hnmib[2] = { CTL_KERN, KERN_HOSTNAME }; + int tfp_r_mib[3] = { CTL_KERN, KERN_TFP, KERN_TFP_READ_GROUP }; + int tfp_rw_mib[3] = { CTL_KERN, KERN_TFP, KERN_TFP_RW_GROUP }; + gid_t tfp_r_gid = 0; + gid_t tfp_rw_gid = 0; + struct group *tfp_gr; uint64_t mem = 0; uint32_t mvn; size_t memsz = sizeof(mem); int pthr_r; - + + if ((tfp_gr = getgrnam("procview"))) { + tfp_r_gid = tfp_gr->gr_gid; + sysctl(tfp_r_mib, 3, NULL, NULL, &tfp_r_gid, sizeof(tfp_r_gid)); + } + + if ((tfp_gr = getgrnam("procmod"))) { + tfp_rw_gid = tfp_gr->gr_gid; + sysctl(tfp_rw_mib, 3, NULL, NULL, &tfp_rw_gid, sizeof(tfp_rw_gid)); + } + setpriority(PRIO_PROCESS, 0, -1); if (setsid() == -1) @@ -2400,3 +2402,19 @@ static void async_callback(void) syslog(LOG_DEBUG, "unexpected: kevent() returned something != 0, -1 or 1"); } } + +static void testfd_or_openfd(int fd, const char *path, int flags) +{ + int tmpfd; + + if (-1 != (tmpfd = dup(fd))) { + close(tmpfd); + } else { + if (-1 == (tmpfd = open(path, flags))) { + syslog(LOG_ERR, "open(\"%s\", ...): %m", path); + } else if (tmpfd != fd) { + dup2(tmpfd, fd); + close(tmpfd); + } + } +} diff --git a/launchd/src/launchd.plist.5 b/launchd/src/launchd.plist.5 index e9ab97a..f6c1f2d 100644 --- a/launchd/src/launchd.plist.5 +++ b/launchd/src/launchd.plist.5 @@ -264,6 +264,8 @@ This optional key implies SockFamily is set to "Unix". It specifies the path to or .Xr bind 2 to. +.It Sy SockPathMode +This optional key specifies the mode of the socket. Known bug: Property lists don't support octal, so please convert the value to decimal. .It Sy Bonjour This optional key can be used to request that the service be registered with the .Xr mDNSResponder 8 . diff --git a/launchd/src/launchdebugd.c b/launchd/src/launchdebugd.c index 7d746c4..3c3d238 100644 --- a/launchd/src/launchdebugd.c +++ b/launchd/src/launchdebugd.c @@ -123,25 +123,29 @@ int main(void) exit(EXIT_SUCCESS); } +static void launch_print_obj_dict_callback(launch_data_t obj, const char *key, void *context) +{ + FILE *w = context; + + fprintf(w, "%s\n", key); + if (launch_data_get_type(obj) != LAUNCH_DATA_ARRAY && + launch_data_get_type(obj) != LAUNCH_DATA_DICTIONARY) + fprintf(w, "
  • \n"); + launch_print_obj(obj, w); + if (launch_data_get_type(obj) != LAUNCH_DATA_ARRAY && + launch_data_get_type(obj) != LAUNCH_DATA_DICTIONARY) + fprintf(w, "
\n"); +} + static void launch_print_obj(launch_data_t o, FILE *w) { size_t i; - void launch_print_obj_dict_callback(launch_data_t obj, const char *key, void *context __attribute__((unused))) { - fprintf(w, "%s\n", key); - if (launch_data_get_type(obj) != LAUNCH_DATA_ARRAY && - launch_data_get_type(obj) != LAUNCH_DATA_DICTIONARY) - fprintf(w, "
  • \n"); - launch_print_obj(obj, w); - if (launch_data_get_type(obj) != LAUNCH_DATA_ARRAY && - launch_data_get_type(obj) != LAUNCH_DATA_DICTIONARY) - fprintf(w, "
\n"); - } switch (launch_data_get_type(o)) { case LAUNCH_DATA_DICTIONARY: fprintf(w, "
  • \n"); - launch_data_dict_iterate(o, launch_print_obj_dict_callback, NULL); + launch_data_dict_iterate(o, launch_print_obj_dict_callback, w); fprintf(w, "
\n"); break; case LAUNCH_DATA_ARRAY: diff --git a/launchd/src/launchproxy.c b/launchd/src/launchproxy.c index 481c8eb..6ab5f23 100644 --- a/launchd/src/launchproxy.c +++ b/launchd/src/launchproxy.c @@ -43,6 +43,10 @@ #include "launch.h" +#if __GNUC__ >= 4 +OSStatus SessionCreate(SessionCreationFlags flags, SessionAttributeBits attributes) __attribute__((weak)); +#endif + static int kq = 0; static void find_fds(launch_data_t o, const char *key __attribute__((unused)), void *context __attribute__((unused))) diff --git a/launchd/src/liblaunch.c b/launchd/src/liblaunch.c index cc23170..87de3cc 100644 --- a/launchd/src/liblaunch.c +++ b/launchd/src/liblaunch.c @@ -20,6 +20,7 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#include #include #include #include @@ -35,8 +36,66 @@ #include "launch.h" #include "launch_priv.h" +/* __OSBogusByteSwap__() must not really exist in the symbol namespace + * in order for the following to generate an error at build time. + */ +extern void __OSBogusByteSwap__(void); + +#define host2big(x) \ + ({ typeof (x) _X, _x = (x); \ + switch (sizeof(_x)) { \ + case 8: \ + _X = OSSwapHostToBigInt64(_x); \ + break; \ + case 4: \ + _X = OSSwapHostToBigInt32(_x); \ + break; \ + case 2: \ + _X = OSSwapHostToBigInt16(_x); \ + break; \ + case 1: \ + _X = _x; \ + break; \ + default: \ + __OSBogusByteSwap__(); \ + break; \ + } \ + _X; \ + }) + + +#define big2host(x) \ + ({ typeof (x) _X, _x = (x); \ + switch (sizeof(_x)) { \ + case 8: \ + _X = OSSwapBigToHostInt64(_x); \ + break; \ + case 4: \ + _X = OSSwapBigToHostInt32(_x); \ + break; \ + case 2: \ + _X = OSSwapBigToHostInt16(_x); \ + break; \ + case 1: \ + _X = _x; \ + break; \ + default: \ + __OSBogusByteSwap__(); \ + break; \ + } \ + _X; \ + }) + + +struct launch_msg_header { + uint64_t magic; + uint64_t len; +}; + +#define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull + struct _launch_data { - launch_data_type_t type; + int type; union { struct { launch_data_t *_array; @@ -464,14 +523,32 @@ void launchd_close(launch_t lh) static void make_msg_and_cmsg(launch_data_t d, void **where, size_t *len, int **fd_where, size_t *fdcnt) { + launch_data_t o_in_w; size_t i; *where = realloc(*where, *len + sizeof(struct _launch_data)); - memcpy(*where + *len, d, sizeof(struct _launch_data)); + + o_in_w = *where + *len; + memset(o_in_w, 0, sizeof(struct _launch_data)); *len += sizeof(struct _launch_data); + o_in_w->type = host2big(d->type); + switch (d->type) { + case LAUNCH_DATA_INTEGER: + o_in_w->number = host2big(d->number); + break; + case LAUNCH_DATA_REAL: + o_in_w->float_num = host2big(d->float_num); + break; + case LAUNCH_DATA_BOOL: + o_in_w->boolean = host2big(d->boolean); + break; + case LAUNCH_DATA_ERRNO: + o_in_w->err = host2big(d->err); + break; case LAUNCH_DATA_FD: + o_in_w->fd = host2big(d->fd); if (d->fd != -1) { *fd_where = realloc(*fd_where, (*fdcnt + 1) * sizeof(int)); (*fd_where)[*fdcnt] = d->fd; @@ -479,17 +556,20 @@ static void make_msg_and_cmsg(launch_data_t d, void **where, size_t *len, int ** } break; case LAUNCH_DATA_STRING: + o_in_w->string_len = host2big(d->string_len); *where = realloc(*where, *len + strlen(d->string) + 1); memcpy(*where + *len, d->string, strlen(d->string) + 1); *len += strlen(d->string) + 1; break; case LAUNCH_DATA_OPAQUE: + o_in_w->opaque_size = host2big(d->opaque_size); *where = realloc(*where, *len + d->opaque_size); memcpy(*where + *len, d->opaque, d->opaque_size); *len += d->opaque_size; break; case LAUNCH_DATA_DICTIONARY: case LAUNCH_DATA_ARRAY: + o_in_w->_array_cnt = host2big(d->_array_cnt); *where = realloc(*where, *len + (d->_array_cnt * sizeof(launch_data_t))); memcpy(*where + *len, d->_array, d->_array_cnt * sizeof(launch_data_t)); *len += d->_array_cnt * sizeof(launch_data_t); @@ -505,42 +585,48 @@ static void make_msg_and_cmsg(launch_data_t d, void **where, size_t *len, int ** static launch_data_t make_data(launch_t conn, size_t *data_offset, size_t *fdoffset) { launch_data_t r = conn->recvbuf + *data_offset; - size_t i; + size_t i, tmpcnt; if ((conn->recvlen - *data_offset) < sizeof(struct _launch_data)) return NULL; *data_offset += sizeof(struct _launch_data); - switch (r->type) { + switch (big2host(r->type)) { case LAUNCH_DATA_DICTIONARY: case LAUNCH_DATA_ARRAY: - if ((conn->recvlen - *data_offset) < (r->_array_cnt * sizeof(launch_data_t))) { + tmpcnt = big2host(r->_array_cnt); + if ((conn->recvlen - *data_offset) < (tmpcnt * sizeof(launch_data_t))) { errno = EAGAIN; return NULL; } r->_array = conn->recvbuf + *data_offset; - *data_offset += r->_array_cnt * sizeof(launch_data_t); - for (i = 0; i < r->_array_cnt; i++) { + *data_offset += tmpcnt * sizeof(launch_data_t); + for (i = 0; i < tmpcnt; i++) { r->_array[i] = make_data(conn, data_offset, fdoffset); if (r->_array[i] == NULL) return NULL; } + r->_array_cnt = tmpcnt; break; case LAUNCH_DATA_STRING: - if ((conn->recvlen - *data_offset) < (r->string_len + 1)) { + tmpcnt = big2host(r->string_len); + if ((conn->recvlen - *data_offset) < (tmpcnt + 1)) { errno = EAGAIN; return NULL; } r->string = conn->recvbuf + *data_offset; - *data_offset += r->string_len + 1; + r->string_len = tmpcnt; + *data_offset += tmpcnt + 1; break; case LAUNCH_DATA_OPAQUE: - if ((conn->recvlen - *data_offset) < r->opaque_size) { + tmpcnt = big2host(r->opaque_size); + if ((conn->recvlen - *data_offset) < tmpcnt) { errno = EAGAIN; return NULL; } r->opaque = conn->recvbuf + *data_offset; - *data_offset += r->opaque_size; + r->opaque_size = tmpcnt; + *data_offset += tmpcnt; break; case LAUNCH_DATA_FD: if (r->fd != -1) { @@ -549,9 +635,16 @@ static launch_data_t make_data(launch_t conn, size_t *data_offset, size_t *fdoff } break; case LAUNCH_DATA_INTEGER: + r->number = big2host(r->number); + break; case LAUNCH_DATA_REAL: + r->float_num = big2host(r->float_num); + break; case LAUNCH_DATA_BOOL: + r->boolean = big2host(r->boolean); + break; case LAUNCH_DATA_ERRNO: + r->err = big2host(r->err); break; default: errno = EINVAL; @@ -559,25 +652,44 @@ static launch_data_t make_data(launch_t conn, size_t *data_offset, size_t *fdoff break; } + r->type = big2host(r->type); + return r; } int launchd_msg_send(launch_t lh, launch_data_t d) { + struct launch_msg_header lmh; struct cmsghdr *cm = NULL; struct msghdr mh; - struct iovec iov; - int r; + struct iovec iov[2]; size_t sentctrllen = 0; + int r; memset(&mh, 0, sizeof(mh)); - mh.msg_iov = &iov; - mh.msg_iovlen = 1; + if (d) { + uint64_t msglen = lh->sendlen; - if (d) make_msg_and_cmsg(d, &lh->sendbuf, &lh->sendlen, &lh->sendfds, &lh->sendfdcnt); + msglen = (lh->sendlen - msglen) + sizeof(struct launch_msg_header); + lmh.len = host2big(msglen); + lmh.magic = host2big(LAUNCH_MSG_HEADER_MAGIC); + + iov[0].iov_base = &lmh; + iov[0].iov_len = sizeof(lmh); + mh.msg_iov = iov; + mh.msg_iovlen = 2; + } else { + mh.msg_iov = iov + 1; + mh.msg_iovlen = 1; + } + + iov[1].iov_base = lh->sendbuf; + iov[1].iov_len = lh->sendlen; + + if (lh->sendfdcnt > 0) { sentctrllen = mh.msg_controllen = CMSG_SPACE(lh->sendfdcnt * sizeof(int)); cm = alloca(mh.msg_controllen); @@ -592,9 +704,6 @@ int launchd_msg_send(launch_t lh, launch_data_t d) memcpy(CMSG_DATA(cm), lh->sendfds, lh->sendfdcnt * sizeof(int)); } - iov.iov_base = lh->sendbuf; - iov.iov_len = lh->sendlen; - if ((r = sendmsg(lh->fd, &mh, 0)) == -1) { return -1; } else if (r == 0) { @@ -605,6 +714,10 @@ int launchd_msg_send(launch_t lh, launch_data_t d) return -1; } + if (d) { + r -= sizeof(struct launch_msg_header); + } + lh->sendlen -= r; if (lh->sendlen > 0) { memmove(lh->sendbuf, lh->sendbuf + r, lh->sendlen); @@ -700,7 +813,7 @@ out: int launchd_msg_recv(launch_t lh, void (*cb)(launch_data_t, void *), void *context) { struct cmsghdr *cm = alloca(4096); - launch_data_t rmsg; + launch_data_t rmsg = NULL; size_t data_offset, fd_offset; struct msghdr mh; struct iovec iov; @@ -734,13 +847,33 @@ int launchd_msg_recv(launch_t lh, void (*cb)(launch_data_t, void *), void *conte lh->recvfdcnt += (mh.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int); } -parse_more: - data_offset = 0; - fd_offset = 0; + r = 0; + + while (lh->recvlen > 0) { + struct launch_msg_header *lmhp = lh->recvbuf; + uint64_t tmplen; + data_offset = sizeof(struct launch_msg_header); + fd_offset = 0; + + if (lh->recvlen < sizeof(struct launch_msg_header)) + goto need_more_data; + + tmplen = big2host(lmhp->len); + + if (big2host(lmhp->magic) != LAUNCH_MSG_HEADER_MAGIC || tmplen <= sizeof(struct launch_msg_header)) { + errno = EBADRPC; + goto out_bad; + } + + if (lh->recvlen < tmplen) { + goto need_more_data; + } - rmsg = make_data(lh, &data_offset, &fd_offset); + if ((rmsg = make_data(lh, &data_offset, &fd_offset)) == NULL) { + errno = EBADRPC; + goto out_bad; + } - if (rmsg) { cb(rmsg, context); lh->recvlen -= data_offset; @@ -758,17 +891,14 @@ parse_more: free(lh->recvfds); lh->recvfds = malloc(0); } - - if (lh->recvlen > 0) - goto parse_more; - else - r = 0; - } else { - errno = EAGAIN; - r = -1; } return r; + +need_more_data: + errno = EAGAIN; +out_bad: + return -1; } launch_data_t launch_data_copy(launch_data_t o) diff --git a/launchd/src/lists.c b/launchd/src/lists.c index 8e3eed7..01d3ef9 100644 --- a/launchd/src/lists.c +++ b/launchd/src/lists.c @@ -278,14 +278,15 @@ delete_bootstrap_services(bootstrap_info_t *bootstrap) if (bootstrap != servicep->bootstrap) continue; - if (!servicep->isActive || !servicep->server) { - delete_service(servicep); - continue; - } - serverp = servicep->server; + + if (servicep->isActive && serverp) + serverp->active_services--; + delete_service(servicep); - serverp->active_services--; + + if (!serverp) + continue; if (!active_server(serverp)) delete_server(serverp); } diff --git a/launchd/src/rc b/launchd/src/rc index 9a89261..551448a 100644 --- a/launchd/src/rc +++ b/launchd/src/rc @@ -252,11 +252,10 @@ if [ -f /Library/Preferences/com.apple.sharing.firewall.plist ]; then fi # Load [ideally on demand] daemons -/usr/libexec/register_mach_bootstrap_servers /etc/mach_init.d if [ "${SafeBoot}" = "-x" ]; then - launchctl load /System/Library/LaunchDaemons + launchctl load /System/Library/LaunchDaemons /etc/mach_init.d else - launchctl load /Library/LaunchDaemons /System/Library/LaunchDaemons + launchctl load /Library/LaunchDaemons /System/Library/LaunchDaemons /etc/mach_init.d SystemStarter ${VerboseFlag} fi diff --git a/launchd/src/register_mach_bootstrap_servers.c b/launchd/src/register_mach_bootstrap_servers.c index 2476911..eb0d7cc 100644 --- a/launchd/src/register_mach_bootstrap_servers.c +++ b/launchd/src/register_mach_bootstrap_servers.c @@ -149,7 +149,7 @@ static CFPropertyListRef CreateMyPropertyListFromFile(const char *posixfile) SInt32 errorCode; CFURLRef fileURL; - fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, posixfile, strlen(posixfile), false); + fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)posixfile, strlen(posixfile), false); if (!fileURL) fprintf(stderr, "%s: CFURLCreateFromFileSystemRepresentation(%s) failed\n", getprogname(), posixfile); if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &errorCode)) diff --git a/launchd/src/wait4path.c b/launchd/src/wait4path.c index 7bc333f..ee1c1ae 100644 --- a/launchd/src/wait4path.c +++ b/launchd/src/wait4path.c @@ -42,6 +42,9 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + if (stat(argv[1], &sb) == 0) + exit(EXIT_SUCCESS); + EV_SET(&kev, 0, EVFILT_FS, EV_ADD, 0, 0, 0); if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) { -- 2.45.2