blob: 39e55b8a532e347bba7b7ea9e25774531a4ae1f7 [file] [log] [blame]
// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/* For background on this, see:
* https://chromium-review.googlesource.com/43885
* https://crosbug.com/39422
*
* Short answer: `xauth` pulls in a lot of legacy libs we don't care about.
*/
#include <arpa/inet.h>
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#if __GLIBC_MINOR__ >= 16
/* New to glibc-2.16 */
#include <sys/auxv.h>
#else
/* Roll our own as long as we have glibc-2.15 */
#include <elf.h>
#include <link.h>
static unsigned long getauxval(unsigned long type)
{
unsigned long val = 0;
ElfW(auxv_t) auxv;
FILE *fp = fopen("/proc/self/auxv", "r");
while (fread(&auxv, sizeof(auxv), 1, fp))
if (auxv.a_type == type) {
val = auxv.a_un.a_val;
break;
}
fclose(fp);
return val;
}
#endif
/* New to glibc-2.16 / gcc-4.7 */
#ifndef static_assert
# define static_assert(cond, msg) \
do { \
(void)(sizeof(char[1 - 2 * !(cond)])); \
} while (0)
#endif
static bool writeu16(FILE *fp, uint16_t val)
{
uint16_t tmp = htons(val);
return fwrite(&tmp, sizeof(tmp), 1, fp) == 1 ? true : false;
}
static bool writelv(FILE *fp, uint16_t len, const char *val)
{
if (!writeu16(fp, len) ||
fwrite(val, len, 1, fp) != 1)
return false;
return true;
}
static bool writestrlv(FILE *fp, const char *str)
{
return writelv(fp, (uint16_t)strlen(str), str);
}
/*
* cros-xauth - ChromeOS MIT-MAGIC-COOKIE-1 generator
*
* Usage: cros-xauth <Xauthority file>
*
* Outputs an xauth cookie equivalent to:
* $ xauth -q -f .Xauthority add :0 . $(mcookie)
*/
int main(int argc, char *argv[])
{
static uint16_t family = 0x100;
static const char address[] = "localhost";
static const char number[] = "0";
static const char name[] = "MIT-MAGIC-COOKIE-1";
char cookie[16];
/* Sanity in an insane world! */
umask(0022);
/* The kernel gives us a pointer to 16 bytes of random data via
* AT_RANDOM. Suck it up as our cookie if possible.
*/
void *at_random = (void *)(uintptr_t)getauxval(AT_RANDOM);
if (!at_random) {
/* Rely on ASLR to give us at least 32 bits of randomness,
* and we'll let garbage on the stack do the rest.
*/
uintptr_t addr = (uintptr_t)&main;
memcpy(cookie, &addr, sizeof(addr));
static_assert(sizeof(addr) <= sizeof(cookie), "cookie/pointer mismatch");
} else {
memcpy(cookie, at_random, 16);
static_assert(16 <= sizeof(cookie), "cookie too small for AT_RANDOM");
}
FILE *fp = fopen(argv[1], "wb");
if (fp == NULL ||
!writeu16(fp, family) ||
!writestrlv(fp, address) ||
!writestrlv(fp, number) ||
!writestrlv(fp, name) ||
!writelv(fp, sizeof(cookie), cookie)) {
perror(argv[0]);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}