#include "headers.h" #define BUFFER 1 #define STRUCT 2 #define PUSHED 4 struct SmbBuffer { uchar *buf; ulong realmaxlen; ulong maxlen; ulong rn; ulong wn; ulong savewn; int flags; }; void smbbufferreset(SmbBuffer *s) { if (s == nil) return; s->rn = 0; s->wn = 0; s->flags &= ~PUSHED; } void smbbuffersetbuf(SmbBuffer *s, void *p, ulong maxlen) { s->realmaxlen = s->maxlen = maxlen; if (s->buf) { if (s->flags & BUFFER) free(s->buf); s->buf = nil; } s->flags &= ~BUFFER; if (p) s->buf = p; else { s->buf = smbemalloc(maxlen); s->flags |= BUFFER; } smbbufferreset(s); } SmbBuffer * smbbufferinit(void *base, void *bdata, ulong blen) { SmbBuffer *b; b = smbemalloc(sizeof(*b)); b->buf = base; b->flags = STRUCT; b->rn = (uchar *)bdata - (uchar *)base; b->wn = b->rn + blen; b->realmaxlen = b->maxlen = b->wn; return b; } int smbbufferalignl2(SmbBuffer *s, int al2) { ulong mask, newn; mask = (1 << al2) - 1; newn = (s->wn + mask) & ~mask; if (newn != s->wn) { if (newn > s->maxlen) return 0; s->wn = newn; } return 1; } int smbbufferputb(SmbBuffer *s, uchar b) { if (s->wn >= s->maxlen) return 0; s->buf[s->wn++] = b; return 1; } ulong smbbufferspace(SmbBuffer *sess) { return sess->maxlen - sess->wn; } int smbbufferoffsetputs(SmbBuffer *sess, ulong offset, ushort s) { if (offset + 2 > sess->wn) return 0; smbhnputs(sess->buf + offset, s); return 1; } int smbbufferputs(SmbBuffer *sess, ushort s) { if (sess->wn + sizeof(ushort) > sess->maxlen) return 0; smbhnputs(sess->buf + sess->wn, s); sess->wn += sizeof(ushort); return 1; } int smbbufferputl(SmbBuffer *s, ulong l) { if (s->wn + sizeof(ulong) > s->maxlen) return 0; smbhnputl(s->buf + s->wn, l); s->wn += sizeof(ulong); return 1; } int smbbufferputv(SmbBuffer *s, vlong v) { if (s->wn + sizeof(vlong) > s->maxlen) return 0; smbhnputv(s->buf + s->wn, v); s->wn += sizeof(vlong); return 1; } int smbbufferputbytes(SmbBuffer *s, void *data, ulong datalen) { if (s->wn + datalen > s->maxlen) return 0; if (data) memcpy(s->buf + s->wn, data, datalen); s->wn += datalen; return 1; } int smbbufferputstring(SmbBuffer *b, SmbPeerInfo *p, ulong flags, char *string) { int n = smbstringput(p, flags, b->buf, b->wn, b->maxlen, string); if (n <= 0) return 0; b->wn += n; return 1; } int smbbufferputstrn(SmbBuffer *s, char *string, int size, int upcase) { int n = smbstrnput(s->buf, s->wn, s->maxlen, string, size, upcase); if (n <= 0) return 0; s->wn += n; return 1; } ulong smbbufferwriteoffset(SmbBuffer *s) { return s->wn; } ulong smbbufferwritemaxoffset(SmbBuffer *s) { return s->maxlen; } ulong smbbufferreadoffset(SmbBuffer *s) { return s->rn; } void * smbbufferreadpointer(SmbBuffer *s) { return s->buf + s->rn; } void * smbbufferwritepointer(SmbBuffer *s) { return s->buf + s->wn; } ulong smbbufferwritespace(SmbBuffer *b) { return b->maxlen - b->wn; } SmbBuffer * smbbuffernew(ulong maxlen) { SmbBuffer *b; b = smbemalloc(sizeof(SmbBuffer)); b->buf = smbemalloc(maxlen); b->realmaxlen = b->maxlen = maxlen; b->rn = 0; b->wn = 0; b->flags = STRUCT | BUFFER; return b; } void smbbufferfree(SmbBuffer **bp) { SmbBuffer *b = *bp; if (b) { if (b->flags & BUFFER) { free(b->buf); b->buf = nil; b->flags &= ~BUFFER; } if (b->flags & STRUCT) free(b); *bp = nil; } } uchar * smbbufferbase(SmbBuffer *b) { return b->buf; } int smbbuffergetbytes(SmbBuffer *b, void *buf, ulong len) { if (b->rn + len > b->wn) return 0; if (buf) memcpy(buf, b->buf + b->rn, len); b->rn += len; return 1; } void smbbuffersetreadlen(SmbBuffer *b, ulong len) { b->wn = b->rn + len; } int smbbuffertrimreadlen(SmbBuffer *b, ulong len) { if (b->rn + len > b->wn) return 0; else if (b->rn + len < b->wn) b->wn = b->rn + len; return 1; } int smbbuffergets(SmbBuffer *b, ushort *sp) { if (b->rn + 2 > b->wn) return 0; *sp = smbnhgets(b->buf + b->rn); b->rn += 2; return 1; } int smbbuffergetstrn(SmbBuffer *b, ushort size, char **sp) { uchar *np; if (size > b->wn - b->rn) return 0; np = memchr(b->buf + b->rn, 0, size); if (np == nil) return 0; *sp = strdup((char *)b->buf + b->rn); b->rn += size; return 1; } int smbbuffergetstr(SmbBuffer *b, ulong flags, char **sp) { int c; char *p; uchar *np; np = memchr(b->buf + b->rn, 0, b->wn - b->rn); if (np == nil) return 0; *sp = strdup((char *)b->buf + b->rn); for (p = *sp; *p != 0; p++) { c = *p; if (c >= 'a' && c <= 'z' && (flags & SMB_STRING_UPCASE)) *p = toupper(c); else if (c == '/' && (flags & SMB_STRING_REVPATH)) *p = '\\'; else if (c == '\\' && (flags & SMB_STRING_PATH)) *p = '/'; else if (smbglobals.convertspace){ if (c == 0xa0 && (flags & SMB_STRING_REVPATH)) *p = ' '; else if (c == ' ' && (flags & SMB_STRING_PATH)) *p = 0xa0; } } b->rn = np - b->buf + 1; return 1; } int smbbuffergetstrinline(SmbBuffer *b, char **sp) { uchar *np; np = memchr(b->buf + b->rn, 0, b->wn - b->rn); if (np == nil) return 0; *sp = (char *)b->buf + b->rn; b->rn = np - b->buf + 1; return 1; } int smbbuffergetucs2(SmbBuffer *b, ulong flags, char **sp) { uchar *bdata = b->buf + b->rn; uchar *edata = b->buf + b->wn; Rune r; int l; char *p, *q; uchar *savebdata; int first; l = 0; if ((flags & SMB_STRING_UNALIGNED) == 0 && (bdata - b->buf) & 1) bdata++; savebdata = bdata; first = 1; do { if (bdata + 2 > edata) { l++; break; } r = smbnhgets(bdata); bdata += 2; if (first && (flags & SMB_STRING_PATH) && r != '\\') l++; first = 0; if (flags & SMB_STRING_CONVERT_MASK) r = smbruneconvert(r, flags); l += runelen(r); } while (r != 0); p = smbemalloc(l); bdata = savebdata; q = p; first = 1; do { if (bdata + 2 > edata) { *q = 0; break; } r = smbnhgets(bdata); bdata += 2; if (first && (flags & SMB_STRING_PATH) && r != '\\') *q++ = '/'; first = 0; if (flags & SMB_STRING_CONVERT_MASK) r = smbruneconvert(r, flags); q += runetochar(q, &r); } while (r != 0); b->rn = bdata - b->buf; *sp = p; return 1; } int smbbuffergetstring(SmbBuffer *b, SmbHeader *h, ulong flags, char **sp) { if (flags & SMB_STRING_UNICODE) return smbbuffergetucs2(b, flags, sp); else if (flags & SMB_STRING_ASCII) return smbbuffergetstr(b, flags, sp); else if (h->flags2 & SMB_FLAGS2_UNICODE) return smbbuffergetucs2(b, flags, sp); else return smbbuffergetstr(b, flags, sp); } void * smbbufferpointer(SmbBuffer *b, ulong offset) { return b->buf + offset; } int smbbuffergetb(SmbBuffer *b, uchar *bp) { if (b->rn < b->wn) { *bp = b->buf[b->rn++]; return 1; } return 0; } int smbbuffergetl(SmbBuffer *b, ulong *lp) { if (b->rn + 4 <= b->wn) { *lp = smbnhgetl(b->buf + b->rn); b->rn += 4; return 1; } return 0; } int smbbuffergetv(SmbBuffer *b, vlong *vp) { if (b->rn + 8 <= b->wn) { *vp = smbnhgetv(b->buf + b->rn); b->rn += 8; return 1; } return 0; } ulong smbbufferreadspace(SmbBuffer *b) { return b->wn - b->rn; } void smbbufferwritelimit(SmbBuffer *b, ulong limit) { if (b->rn + limit < b->maxlen) b->maxlen = b->rn + limit; } int smbbufferreadskipto(SmbBuffer *b, ulong offset) { if (offset < b->rn || offset >= b->wn) return 0; b->rn = offset; return 1; } int smbbufferpushreadlimit(SmbBuffer *b, ulong limit) { if (b->flags & PUSHED) return 0; if (limit > b->wn || limit < b->rn) return 0; b->savewn = b->wn; b->wn = limit; b->flags |= PUSHED; return 1; } int smbbufferpopreadlimit(SmbBuffer *b) { if ((b->flags & PUSHED) == 0) return 0; b->wn = b->savewn; b->flags &= ~PUSHED; return 1; } int smbbufferwritebackup(SmbBuffer *b, ulong offset) { if (offset >= b->rn && offset <= b->wn) { b->wn = offset; return 1; } return 0; } int smbbufferreadbackup(SmbBuffer *b, ulong offset) { if (offset <= b->rn) { b->rn = offset; return 1; } return 0; } int smbbufferfixuprelatives(SmbBuffer *b, ulong fixupoffset) { ulong fixval; if (fixupoffset < b->rn || fixupoffset > b->wn - 2) return 0; fixval = b->wn - fixupoffset - 2; if (fixval > 65535) return 0; smbhnputs(b->buf + fixupoffset, fixval); return 1; } int smbbufferfixuprelativel(SmbBuffer *b, ulong fixupoffset) { ulong fixval; if (fixupoffset < b->rn || fixupoffset > b->wn - 4) return 0; fixval = b->wn - fixupoffset - 4; smbhnputl(b->buf + fixupoffset, fixval); return 1; } int smbbufferfixupabsolutes(SmbBuffer *b, ulong fixupoffset) { if (fixupoffset < b->rn || fixupoffset > b->wn - 2) return 0; if (b->wn > 65535) return 0; smbhnputs(b->buf + fixupoffset, b->wn); return 1; } int smbbufferfixupl(SmbBuffer *b, ulong fixupoffset, ulong fixupval) { if (fixupoffset < b->rn || fixupoffset > b->wn - 4) return 0; smbhnputl(b->buf + fixupoffset, fixupval); return 1; } int smbbufferfixupabsolutel(SmbBuffer *b, ulong fixupoffset) { if (fixupoffset < b->rn || fixupoffset > b->wn - 2) return 0; smbhnputl(b->buf + fixupoffset, b->wn); return 1; } int smbbufferfixuprelativeinclusivel(SmbBuffer *b, ulong fixupoffset) { if (fixupoffset < b->rn || fixupoffset > b->wn - 4) return 0; smbhnputl(b->buf + fixupoffset, b->wn - fixupoffset); return 1; } int smbbufferfill(SmbBuffer *b, uchar val, ulong len) { if (b->maxlen - b->wn < len) return 0; memset(b->buf + b->wn, val, len); b->wn += len; return 1; } int smbbufferoffsetgetb(SmbBuffer *b, ulong offset, uchar *bp) { if (offset >= b->rn && offset + 1 <= b->wn) { *bp = b->buf[b->rn + offset]; return 1; } return 0; } int smbbuffercopy(SmbBuffer *to, SmbBuffer *from, ulong amount) { if (smbbufferreadspace(from) < amount) return 0; if (smbbufferputbytes(to, smbbufferreadpointer(from), amount)) { assert(smbbuffergetbytes(from, nil, amount)); return 1; } return 0; } int smbbufferoffsetcopystr(SmbBuffer *b, ulong offset, char *buf, int buflen, int *lenp) { uchar *np; if (offset < b->rn || offset >= b->wn) return 0; np = memchr(b->buf + offset, 0, b->wn - offset); if (np == nil) return 0; *lenp = np - (b->buf + offset) + 1; if (*lenp > buflen) return 0; memcpy(buf, b->buf + offset, *lenp); return 1; }