int xp_getpwent(Xpnode *nd, char *adminkey, char ***pwent) { char *buf = NULL, **toks; int n, bufsize = 8192; Xkey *akey = NULL; Spuser *auser = NULL; Spcfsys *fs = NULL; Spcfid *fid = NULL; if (adminkey) { akey = xauth_privkey_create(adminkey); if (!akey) goto error; } if (xp_defaultuser(&auser, &akey) < 0) goto error; fs = xp_node_mount(nd, auser, akey); if (!fs) { fs = xp_node_mount(nd, NULL, akey); if (!fs) goto error; } fid = spc_open(fs, "pwent", Oread); if (!fid) goto error; buf = sp_malloc(sizeof(*buf) * bufsize); if (!buf) goto error; n = spc_read(fid, (u8 *) buf, bufsize-1, 0); if (n < 0) goto error; buf[bufsize] = '\0'; spc_close(fid); spc_umount(fs); n = tokenize(buf, &toks); if (n < 0) goto error; free(buf); xauth_destroy(akey); *pwent = toks; return n; error: if (fid) spc_close(fid); if (fs) spc_umount(fs); if (buf) free(buf); if (akey) xauth_destroy(akey); return -1; }
spc_value_t spc_deserialize_value(reader_t* reader) { spc_value_t value; value.type = spc_read_uint32(reader); switch (value.type) { case SPC_TYPE_NULL: break; case SPC_TYPE_BOOL: value.value.u64 = spc_read_uint32(reader); break; case SPC_TYPE_UINT64: value.value.u64 = spc_read_uint64(reader); break; case SPC_TYPE_INT64: value.value.i64 = spc_read_int64(reader); break; case SPC_TYPE_DOUBLE: value.value.dbl = spc_read_double(reader); break; case SPC_TYPE_STRING: spc_read_uint32(reader); value.value.str = strdup(spc_read_str(reader)); break; case SPC_TYPE_ARRAY: value.value.array = spc_deserialize_array(reader); break; case SPC_TYPE_DICT: value.value.dict = spc_deserialize_dict(reader); break; case SPC_TYPE_SEND_PORT: value.value.port = spc_reader_next_port(reader); break; case SPC_TYPE_RECV_PORT: value.value.port = spc_reader_next_port(reader); break; case SPC_TYPE_UUID: value.value.ptr = malloc(0x10); memcpy(value.value.ptr, spc_read(reader, 0x10), 0x10); break; case SPC_TYPE_DATA: value.value.data.size = spc_read_uint32(reader); value.value.data.ptr = malloc(value.value.data.size); memcpy(value.value.data.ptr, spc_read_padded(reader, value.value.data.size), value.value.data.size); break; default: printf("Unsupported value type: 0x%x\n", value.type); exit(-1); } return value; }
spc_message_t* spc_deserialize(spc_mach_message_t* mach_msg) { reader_t reader; reader.next_port = 0; reader.num_ports = 0; reader.ports = NULL; reader.end = (unsigned char*)mach_msg + mach_msg->header.msgh_size; reader.ptr = mach_msg->buf; // Handle well-known message IDs if (mach_msg->header.msgh_id == MSGID_CONNECTION_INTERRUPTED) { spc_dictionary_t* dict = spc_dictionary_create(); spc_dictionary_set_string(dict, "error", "Connection interrupted"); printf("Connection interrupted\n"); // TODO exit(-1); } if (mach_msg->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { mach_msg_body_t* body = (mach_msg_body_t*)spc_read(&reader, sizeof(mach_msg_body_t)); for (int i = 0; i < body->msgh_descriptor_count; i++) { mach_msg_descriptor_type_t type = ((mach_msg_type_descriptor_t*)reader.ptr)->type; switch (type) { case MACH_MSG_PORT_DESCRIPTOR: { reader.ports = realloc(reader.ports, (reader.num_ports + 1) * sizeof(spc_port_t)); mach_msg_port_descriptor_t* descriptor = (mach_msg_port_descriptor_t*)spc_read(&reader, sizeof(mach_msg_port_descriptor_t)); reader.ports[reader.num_ports].name = descriptor->name; reader.ports[reader.num_ports].type = descriptor->disposition; reader.num_ports += 1; break; } case MACH_MSG_OOL_DESCRIPTOR: spc_read(&reader, sizeof(mach_msg_ool_descriptor_t)); printf("Warning: ignoring OOL descriptor\n"); break; case MACH_MSG_OOL_PORTS_DESCRIPTOR: spc_read(&reader, sizeof(mach_msg_ool_ports_descriptor_t)); printf("Warning: ignoring OOL ports descriptor\n"); break; default: printf("Unsupported mach message descriptor type: %d\n", type); exit(-1); } } } void* header = spc_read(&reader, 8); memcpy(last_header, header, 8); spc_value_t value = spc_deserialize_value(&reader); if (value.type != SPC_TYPE_DICT) { spc_value_destroy(value); puts("Invalid XPC message type"); return NULL; } spc_message_t* msg = malloc(sizeof(spc_message_t)); msg->remote_port.name = mach_msg->header.msgh_remote_port; msg->remote_port.type = MACH_MSGH_BITS_REMOTE(mach_msg->header.msgh_bits); msg->local_port.name = mach_msg->header.msgh_remote_port; msg->local_port.type = MACH_MSGH_BITS_LOCAL(mach_msg->header.msgh_bits); msg->id = mach_msg->header.msgh_id; msg->content = value.value.dict; return msg; }
void* spc_read_padded(reader_t* reader, size_t size) { size_t remainder = (4 - (size % 4)) % 4; return spc_read(reader, size + remainder); }
uint32_t spc_read_uint32(reader_t* reader) { return *(uint32_t*)spc_read(reader, 4); }
double spc_read_double(reader_t* reader) { return *(double*)spc_read(reader, 8); }
int64_t spc_read_int64(reader_t* reader) { return *(int64_t*)spc_read(reader, 8); }
int main(int argc, char **argv) { int i, n, off; int c; char *addr; char *path; Spuser *user; Spcfsys *fs; Spcfid *fid; char buf[512]; user = sp_unix_users->uid2user(sp_unix_users, geteuid()); while ((c = getopt(argc, argv, "dp:")) != -1) { switch (c) { case 'd': spc_chatty = 1; break; case 'u': user = sp_unix_users->uname2user(sp_unix_users, optarg); break; default: usage(); } } if (!user) { fprintf(stderr, "cannot retrieve user %d\n", geteuid()); exit(1); } if (argc - optind < 2) usage(); addr = argv[optind]; path = argv[optind+1]; fs = spc_netmount(addr, user, 564, NULL, NULL); fid = spc_open(fs, path, Oread); if (!fid) { fprintf(stderr, "cannot open\n"); exit(1); } off = 0; while ((n = spc_read(fid, (u8*) buf, sizeof(buf), off)) > 0) { i = write(1, buf, n); if (i != n) { fprintf(stderr, "error writing\n"); exit(1); } off += n; } spc_close(fid); spc_umount(fs); exit(0); }