marshal.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #ifndef PUTTY_MARSHAL_H
  2. #define PUTTY_MARSHAL_H
  3. #include "defs.h"
  4. /*
  5. * A sort of 'abstract base class' or 'interface' or 'trait' which is
  6. * the common feature of all types that want to accept data formatted
  7. * using the SSH binary conventions of uint32, string, mpint etc.
  8. */
  9. struct BinarySink {
  10. void (*write)(BinarySink *sink, const void *data, size_t len);
  11. BinarySink *binarysink_;
  12. };
  13. /*
  14. * To define a structure type as a valid target for binary formatted
  15. * data, put 'BinarySink_IMPLEMENTATION' in its declaration, and when
  16. * an instance is set up, use 'BinarySink_INIT' to initialise the
  17. * 'base class' state, providing a function pointer to be the
  18. * implementation of the write() call above.
  19. */
  20. #define BinarySink_IMPLEMENTATION BinarySink binarysink_[1]
  21. #define BinarySink_INIT(obj, writefn) \
  22. ((obj)->binarysink_->write = (writefn), \
  23. (obj)->binarysink_->binarysink_ = (obj)->binarysink_)
  24. /*
  25. * The implementing type's write function will want to downcast its
  26. * 'BinarySink *' parameter back to the more specific type. Also,
  27. * sometimes you'll want to upcast a pointer to a particular
  28. * implementing type into an abstract 'BinarySink *' to pass to
  29. * generic subroutines not defined in this file. These macros do that
  30. * job.
  31. *
  32. * Importantly, BinarySink_UPCAST can also be applied to a BinarySink
  33. * * itself (and leaves it unchanged). That's achieved by a small
  34. * piece of C trickery: implementing structures and the BinarySink
  35. * structure itself both contain a field called binarysink_, but in
  36. * implementing objects it's a BinarySink[1] whereas in the abstract
  37. * type it's a 'BinarySink *' pointing back to the same structure,
  38. * meaning that you can say 'foo->binarysink_' in either case and get
  39. * a pointer type by different methods.
  40. */
  41. #define BinarySink_DOWNCAST(object, type) \
  42. TYPECHECK((object) == ((type *)0)->binarysink_, \
  43. ((type *)(((char *)(object)) - offsetof(type, binarysink_))))
  44. #define BinarySink_UPCAST(object) \
  45. TYPECHECK((object)->binarysink_ == (BinarySink *)0, \
  46. (object)->binarysink_)
  47. /*
  48. * If you structure-copy an object that's implementing BinarySink,
  49. * then that tricky self-pointer in its trait subobject will point to
  50. * the wrong place. You could call BinarySink_INIT again, but this
  51. * macro is terser and does all that's needed to fix up the copied
  52. * object.
  53. */
  54. #define BinarySink_COPIED(obj) \
  55. ((obj)->binarysink_->binarysink_ = (obj)->binarysink_)
  56. /*
  57. * The put_* macros are the main client to this system. Any structure
  58. * which implements the BinarySink 'trait' is valid for use as the
  59. * first parameter of any of these put_* macros.
  60. */
  61. /* Basic big-endian integer types. uint64 is the structure type
  62. * defined in int64.h, not the C99 built-in type. */
  63. #define put_byte(bs, val) \
  64. BinarySink_put_byte(BinarySink_UPCAST(bs), val)
  65. #define put_uint16(bs, val) \
  66. BinarySink_put_uint16(BinarySink_UPCAST(bs), val)
  67. #define put_uint32(bs, val) \
  68. BinarySink_put_uint32(BinarySink_UPCAST(bs), val)
  69. #define put_uint64(bs, val) \
  70. BinarySink_put_uint64(BinarySink_UPCAST(bs), val)
  71. /* SSH booleans, encoded as a single byte storing either 0 or 1. */
  72. #define put_bool(bs, val) \
  73. BinarySink_put_bool(BinarySink_UPCAST(bs), val)
  74. /* SSH strings, with a leading uint32 length field. 'stringz' is a
  75. * convenience function that takes an ordinary C zero-terminated
  76. * string as input. 'stringsb' takes a strbuf * as input, and
  77. * finalises it as a side effect (handy for multi-level marshalling in
  78. * which you use these same functions to format an inner blob of data
  79. * that then gets wrapped into a string container in an outer one). */
  80. #define put_string(bs, val, len) \
  81. BinarySink_put_string(BinarySink_UPCAST(bs),val,len)
  82. #define put_stringpl(bs, ptrlen) \
  83. BinarySink_put_stringpl(BinarySink_UPCAST(bs),ptrlen)
  84. #define put_stringz(bs, val) \
  85. BinarySink_put_stringz(BinarySink_UPCAST(bs), val)
  86. #define put_stringsb(bs, val) \
  87. BinarySink_put_stringsb(BinarySink_UPCAST(bs), val)
  88. /* Other string outputs: 'asciz' emits the string data directly into
  89. * the output including the terminating \0, and 'pstring' emits the
  90. * string in Pascal style with a leading _one_-byte length field.
  91. * pstring can fail if the string is too long. */
  92. #define put_asciz(bs, val) \
  93. BinarySink_put_asciz(BinarySink_UPCAST(bs), val)
  94. #define put_pstring(bs, val) \
  95. BinarySink_put_pstring(BinarySink_UPCAST(bs), val)
  96. /* Multiprecision integers, in both the SSH-1 and SSH-2 formats. */
  97. #define put_mp_ssh1(bs, val) \
  98. BinarySink_put_mp_ssh1(BinarySink_UPCAST(bs), val)
  99. #define put_mp_ssh2(bs, val) \
  100. BinarySink_put_mp_ssh2(BinarySink_UPCAST(bs), val)
  101. /* Padding with a specified byte. */
  102. #define put_padding(bs, len, padbyte) \
  103. BinarySink_put_padding(BinarySink_UPCAST(bs), len, padbyte)
  104. /* Fallback: just emit raw data bytes, using a syntax that matches the
  105. * rest of these macros. */
  106. #define put_data(bs, val, len) \
  107. BinarySink_put_data(BinarySink_UPCAST(bs), val, len)
  108. /*
  109. * The underlying real C functions that implement most of those
  110. * macros. Generally you won't want to call these directly, because
  111. * they have such cumbersome names; you call the wrapper macros above
  112. * instead.
  113. *
  114. * A few functions whose wrapper macros are defined above are actually
  115. * declared in other headers, so as to guarantee that the
  116. * declaration(s) of their other parameter type(s) are in scope.
  117. */
  118. void BinarySink_put_data(BinarySink *, const void *data, size_t len);
  119. void BinarySink_put_padding(BinarySink *, size_t len, unsigned char padbyte);
  120. void BinarySink_put_byte(BinarySink *, unsigned char);
  121. void BinarySink_put_bool(BinarySink *, int);
  122. void BinarySink_put_uint16(BinarySink *, unsigned long);
  123. void BinarySink_put_uint32(BinarySink *, unsigned long);
  124. void BinarySink_put_string(BinarySink *, const void *data, size_t len);
  125. void BinarySink_put_stringpl(BinarySink *, ptrlen);
  126. void BinarySink_put_stringz(BinarySink *, const char *str);
  127. struct strbuf;
  128. void BinarySink_put_stringsb(BinarySink *, struct strbuf *);
  129. void BinarySink_put_asciz(BinarySink *, const char *str);
  130. int BinarySink_put_pstring(BinarySink *, const char *str);
  131. /* ---------------------------------------------------------------------- */
  132. /*
  133. * A complementary trait structure for _un_-marshalling.
  134. *
  135. * This structure contains client-visible data fields rather than
  136. * methods, because that seemed more useful than leaving it totally
  137. * opaque. But it's still got the self-pointer system that will allow
  138. * the set of get_* macros to target one of these itself or any other
  139. * type that 'derives' from it. So, for example, an SSH packet
  140. * structure can act as a BinarySource while also having additional
  141. * fields like the packet type.
  142. */
  143. typedef enum BinarySourceError {
  144. BSE_NO_ERROR,
  145. BSE_OUT_OF_DATA,
  146. BSE_INVALID
  147. } BinarySourceError;
  148. struct BinarySource {
  149. /*
  150. * (data, len) is the data block being decoded. pos is the current
  151. * position within the block.
  152. */
  153. const void *data;
  154. size_t pos, len;
  155. /*
  156. * 'err' indicates whether a decoding error has happened at any
  157. * point. Once this has been set to something other than
  158. * BSE_NO_ERROR, it shouldn't be changed by any unmarshalling
  159. * function. So you can safely do a long sequence of get_foo()
  160. * operations and then test err just once at the end, rather than
  161. * having to conditionalise every single get.
  162. *
  163. * The unmarshalling functions should always return some value,
  164. * even if a decoding error occurs. Generally on error they'll
  165. * return zero (if numeric) or the empty string (if string-based),
  166. * or some other appropriate default value for more complicated
  167. * types.
  168. *
  169. * If the usual return value is dynamically allocated (e.g. a
  170. * Bignum, or a normal C 'char *' string), then the error value is
  171. * also dynamic in the same way. So you have to free exactly the
  172. * same set of things whether or not there was a decoding error,
  173. * which simplifies exit paths - for example, you could call a big
  174. * pile of get_foo functions, then put the actual handling of the
  175. * results under 'if (!get_err(src))', and then free everything
  176. * outside that if.
  177. */
  178. BinarySourceError err;
  179. /*
  180. * Self-pointer for the implicit derivation trick, same as
  181. * BinarySink above.
  182. */
  183. BinarySource *binarysource_;
  184. };
  185. /*
  186. * Implementation macros, similar to BinarySink.
  187. */
  188. #define BinarySource_IMPLEMENTATION BinarySource binarysource_[1]
  189. #define BinarySource_INIT__(obj, data_, len_) \
  190. ((obj)->data = (data_), \
  191. (obj)->len = (len_), \
  192. (obj)->pos = 0, \
  193. (obj)->err = BSE_NO_ERROR, \
  194. (obj)->binarysource_ = (obj))
  195. #define BinarySource_BARE_INIT(obj, data_, len_) \
  196. TYPECHECK(&(obj)->binarysource_ == (BinarySource **)0, \
  197. BinarySource_INIT__(obj, data_, len_))
  198. #define BinarySource_INIT(obj, data_, len_) \
  199. TYPECHECK(&(obj)->binarysource_ == (BinarySource (*)[1])0, \
  200. BinarySource_INIT__(BinarySource_UPCAST(obj), data_, len_))
  201. #define BinarySource_DOWNCAST(object, type) \
  202. TYPECHECK((object) == ((type *)0)->binarysource_, \
  203. ((type *)(((char *)(object)) - offsetof(type, binarysource_))))
  204. #define BinarySource_UPCAST(object) \
  205. TYPECHECK((object)->binarysource_ == (BinarySource *)0, \
  206. (object)->binarysource_)
  207. #define BinarySource_COPIED(obj) \
  208. ((obj)->binarysource_->binarysource_ = (obj)->binarysource_)
  209. #define get_data(src, len) \
  210. BinarySource_get_data(BinarySource_UPCAST(src), len)
  211. #define get_byte(src) \
  212. BinarySource_get_byte(BinarySource_UPCAST(src))
  213. #define get_bool(src) \
  214. BinarySource_get_bool(BinarySource_UPCAST(src))
  215. #define get_uint16(src) \
  216. BinarySource_get_uint16(BinarySource_UPCAST(src))
  217. #define get_uint32(src) \
  218. BinarySource_get_uint32(BinarySource_UPCAST(src))
  219. #define get_uint64(src) \
  220. BinarySource_get_uint64(BinarySource_UPCAST(src))
  221. #define get_string(src) \
  222. BinarySource_get_string(BinarySource_UPCAST(src))
  223. #define get_asciz(src) \
  224. BinarySource_get_asciz(BinarySource_UPCAST(src))
  225. #define get_pstring(src) \
  226. BinarySource_get_pstring(BinarySource_UPCAST(src))
  227. #define get_mp_ssh1(src) \
  228. BinarySource_get_mp_ssh1(BinarySource_UPCAST(src))
  229. #define get_mp_ssh2(src) \
  230. BinarySource_get_mp_ssh2(BinarySource_UPCAST(src))
  231. #define get_rsa_ssh1_pub(src, rsa, order) \
  232. BinarySource_get_rsa_ssh1_pub(BinarySource_UPCAST(src), rsa, order)
  233. #define get_rsa_ssh1_priv(src, rsa) \
  234. BinarySource_get_rsa_ssh1_priv(BinarySource_UPCAST(src), rsa)
  235. #define get_err(src) (BinarySource_UPCAST(src)->err)
  236. #define get_avail(src) (BinarySource_UPCAST(src)->len - \
  237. BinarySource_UPCAST(src)->pos)
  238. #define get_ptr(src) \
  239. ((const void *)( \
  240. (const unsigned char *)(BinarySource_UPCAST(src)->data) + \
  241. BinarySource_UPCAST(src)->pos))
  242. ptrlen BinarySource_get_data(BinarySource *, size_t);
  243. unsigned char BinarySource_get_byte(BinarySource *);
  244. int BinarySource_get_bool(BinarySource *);
  245. unsigned BinarySource_get_uint16(BinarySource *);
  246. unsigned long BinarySource_get_uint32(BinarySource *);
  247. ptrlen BinarySource_get_string(BinarySource *);
  248. const char *BinarySource_get_asciz(BinarySource *);
  249. ptrlen BinarySource_get_pstring(BinarySource *);
  250. #endif /* PUTTY_MARSHAL_H */