lua/lfunc.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 23 Jun 2017 17:28:03 -0400
changeset 58 1390348facc7
parent 0 d7ee4e2ed49d
permissions -rw-r--r--
Command line tool that decrypts an OPVault keychain and dumps it to stdout.

To compile: gcc -o opvault opvault.c cJSON.c -lcrypto

Usage: ./opvault </path/to/mykeychain.opvault> <password>

This is just a proof of concept; I'll be recycling this into proper OPVault
support in 1pass later and deleting this tool.

This uses OpenSSL's libcrypto for the math instead of all the homegrown
crypto this project is otherwise using. I'll probably migrate the rest in
this direction, too, since this wasn't as bad as I expected to use and
gets you all the package-manager mojo of automatic bug fixes and security
patches and shared code, etc.

cJSON parses JSON in C. That is from https://github.com/DaveGamble/cJSON

An example OPVault keychain from AgileBits is available here:

https://cache.agilebits.com/security-kb/
icculus@0
     1
/*
icculus@0
     2
** $Id: lfunc.c,v 2.30.1.1 2013/04/12 18:48:47 roberto Exp $
icculus@0
     3
** Auxiliary functions to manipulate prototypes and closures
icculus@0
     4
** See Copyright Notice in lua.h
icculus@0
     5
*/
icculus@0
     6
icculus@0
     7
icculus@0
     8
#include <stddef.h>
icculus@0
     9
icculus@0
    10
#define lfunc_c
icculus@0
    11
#define LUA_CORE
icculus@0
    12
icculus@0
    13
#include "lua.h"
icculus@0
    14
icculus@0
    15
#include "lfunc.h"
icculus@0
    16
#include "lgc.h"
icculus@0
    17
#include "lmem.h"
icculus@0
    18
#include "lobject.h"
icculus@0
    19
#include "lstate.h"
icculus@0
    20
icculus@0
    21
icculus@0
    22
icculus@0
    23
Closure *luaF_newCclosure (lua_State *L, int n) {
icculus@0
    24
  Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl;
icculus@0
    25
  c->c.nupvalues = cast_byte(n);
icculus@0
    26
  return c;
icculus@0
    27
}
icculus@0
    28
icculus@0
    29
icculus@0
    30
Closure *luaF_newLclosure (lua_State *L, int n) {
icculus@0
    31
  Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl;
icculus@0
    32
  c->l.p = NULL;
icculus@0
    33
  c->l.nupvalues = cast_byte(n);
icculus@0
    34
  while (n--) c->l.upvals[n] = NULL;
icculus@0
    35
  return c;
icculus@0
    36
}
icculus@0
    37
icculus@0
    38
icculus@0
    39
UpVal *luaF_newupval (lua_State *L) {
icculus@0
    40
  UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv;
icculus@0
    41
  uv->v = &uv->u.value;
icculus@0
    42
  setnilvalue(uv->v);
icculus@0
    43
  return uv;
icculus@0
    44
}
icculus@0
    45
icculus@0
    46
icculus@0
    47
UpVal *luaF_findupval (lua_State *L, StkId level) {
icculus@0
    48
  global_State *g = G(L);
icculus@0
    49
  GCObject **pp = &L->openupval;
icculus@0
    50
  UpVal *p;
icculus@0
    51
  UpVal *uv;
icculus@0
    52
  while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
icculus@0
    53
    GCObject *o = obj2gco(p);
icculus@0
    54
    lua_assert(p->v != &p->u.value);
icculus@0
    55
    lua_assert(!isold(o) || isold(obj2gco(L)));
icculus@0
    56
    if (p->v == level) {  /* found a corresponding upvalue? */
icculus@0
    57
      if (isdead(g, o))  /* is it dead? */
icculus@0
    58
        changewhite(o);  /* resurrect it */
icculus@0
    59
      return p;
icculus@0
    60
    }
icculus@0
    61
    pp = &p->next;
icculus@0
    62
  }
icculus@0
    63
  /* not found: create a new one */
icculus@0
    64
  uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv;
icculus@0
    65
  uv->v = level;  /* current value lives in the stack */
icculus@0
    66
  uv->u.l.prev = &g->uvhead;  /* double link it in `uvhead' list */
icculus@0
    67
  uv->u.l.next = g->uvhead.u.l.next;
icculus@0
    68
  uv->u.l.next->u.l.prev = uv;
icculus@0
    69
  g->uvhead.u.l.next = uv;
icculus@0
    70
  lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
icculus@0
    71
  return uv;
icculus@0
    72
}
icculus@0
    73
icculus@0
    74
icculus@0
    75
static void unlinkupval (UpVal *uv) {
icculus@0
    76
  lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
icculus@0
    77
  uv->u.l.next->u.l.prev = uv->u.l.prev;  /* remove from `uvhead' list */
icculus@0
    78
  uv->u.l.prev->u.l.next = uv->u.l.next;
icculus@0
    79
}
icculus@0
    80
icculus@0
    81
icculus@0
    82
void luaF_freeupval (lua_State *L, UpVal *uv) {
icculus@0
    83
  if (uv->v != &uv->u.value)  /* is it open? */
icculus@0
    84
    unlinkupval(uv);  /* remove from open list */
icculus@0
    85
  luaM_free(L, uv);  /* free upvalue */
icculus@0
    86
}
icculus@0
    87
icculus@0
    88
icculus@0
    89
void luaF_close (lua_State *L, StkId level) {
icculus@0
    90
  UpVal *uv;
icculus@0
    91
  global_State *g = G(L);
icculus@0
    92
  while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) {
icculus@0
    93
    GCObject *o = obj2gco(uv);
icculus@0
    94
    lua_assert(!isblack(o) && uv->v != &uv->u.value);
icculus@0
    95
    L->openupval = uv->next;  /* remove from `open' list */
icculus@0
    96
    if (isdead(g, o))
icculus@0
    97
      luaF_freeupval(L, uv);  /* free upvalue */
icculus@0
    98
    else {
icculus@0
    99
      unlinkupval(uv);  /* remove upvalue from 'uvhead' list */
icculus@0
   100
      setobj(L, &uv->u.value, uv->v);  /* move value to upvalue slot */
icculus@0
   101
      uv->v = &uv->u.value;  /* now current value lives here */
icculus@0
   102
      gch(o)->next = g->allgc;  /* link upvalue into 'allgc' list */
icculus@0
   103
      g->allgc = o;
icculus@0
   104
      luaC_checkupvalcolor(g, uv);
icculus@0
   105
    }
icculus@0
   106
  }
icculus@0
   107
}
icculus@0
   108
icculus@0
   109
icculus@0
   110
Proto *luaF_newproto (lua_State *L) {
icculus@0
   111
  Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p;
icculus@0
   112
  f->k = NULL;
icculus@0
   113
  f->sizek = 0;
icculus@0
   114
  f->p = NULL;
icculus@0
   115
  f->sizep = 0;
icculus@0
   116
  f->code = NULL;
icculus@0
   117
  f->cache = NULL;
icculus@0
   118
  f->sizecode = 0;
icculus@0
   119
  f->lineinfo = NULL;
icculus@0
   120
  f->sizelineinfo = 0;
icculus@0
   121
  f->upvalues = NULL;
icculus@0
   122
  f->sizeupvalues = 0;
icculus@0
   123
  f->numparams = 0;
icculus@0
   124
  f->is_vararg = 0;
icculus@0
   125
  f->maxstacksize = 0;
icculus@0
   126
  f->locvars = NULL;
icculus@0
   127
  f->sizelocvars = 0;
icculus@0
   128
  f->linedefined = 0;
icculus@0
   129
  f->lastlinedefined = 0;
icculus@0
   130
  f->source = NULL;
icculus@0
   131
  return f;
icculus@0
   132
}
icculus@0
   133
icculus@0
   134
icculus@0
   135
void luaF_freeproto (lua_State *L, Proto *f) {
icculus@0
   136
  luaM_freearray(L, f->code, f->sizecode);
icculus@0
   137
  luaM_freearray(L, f->p, f->sizep);
icculus@0
   138
  luaM_freearray(L, f->k, f->sizek);
icculus@0
   139
  luaM_freearray(L, f->lineinfo, f->sizelineinfo);
icculus@0
   140
  luaM_freearray(L, f->locvars, f->sizelocvars);
icculus@0
   141
  luaM_freearray(L, f->upvalues, f->sizeupvalues);
icculus@0
   142
  luaM_free(L, f);
icculus@0
   143
}
icculus@0
   144
icculus@0
   145
icculus@0
   146
/*
icculus@0
   147
** Look for n-th local variable at line `line' in function `func'.
icculus@0
   148
** Returns NULL if not found.
icculus@0
   149
*/
icculus@0
   150
const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
icculus@0
   151
  int i;
icculus@0
   152
  for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
icculus@0
   153
    if (pc < f->locvars[i].endpc) {  /* is variable active? */
icculus@0
   154
      local_number--;
icculus@0
   155
      if (local_number == 0)
icculus@0
   156
        return getstr(f->locvars[i].varname);
icculus@0
   157
    }
icculus@0
   158
  }
icculus@0
   159
  return NULL;  /* not found */
icculus@0
   160
}
icculus@0
   161