#include #include #include #include "ncp.h" /* nameing - pb32() == put, bigendian, 32bit value etc. */ int ncphdr(Session *s, int func, int type) { s->type = type; s->p = s->buf; memset(s->buf, 0, s->mtu); pb32(s, s->txsig); // signature pb32(s, 0); // packet len (filled in later) pb32(s, NCPVER); // packet version pb32(s, s->mtu); // max reply length pb16(s, Mrequest); // packet type = request p8(s, s->seq); // sequence number p8(s, s->conn & 0xff); // server's connection # MSB p8(s, s->task); // client's transaction nesting p8(s, (s->conn >> 8) & 0xff); // server's connection # MSB p8(s, (func >> 8) & 0xff); // function # MSB switch(s->type){ case Tvarlen: pb16(s, 0); // subfunction length (filled in later) p8(s, func & 0xff); // subfunction code break; case Tsubfun: p8(s, func & 0xff); // subfunction code break; case Tsimple: break; default: sysfatal("internal error: bad subfunc type 0x%02x\n", type); } return 0; } static int getpkt(Session *s) { long sig; int want, got; uchar preamble = s->rxsig >> 24; s->p = s->buf; memset(s->buf, 0, s->mtu); do { if (read(s->fd, s->p, 1) < 1) return -1; } while (*s->p != preamble); s->p++; want = 7; if ((got = readn(s->fd, s->p, want)) != want){ if (got >= 0) werrstr("media: short read (%d < %d)", got, want); return -1; } s->p = s->buf; if ((sig = gb32(s)) != s->rxsig){ werrstr("media: bad packet signature (%lux != %lux)", sig, s->rxsig); return -1; } if ((s->rxlen = gb32(s)) > s->mtu){ werrstr("media: packet too big (%d > %d)", s->rxlen, s->mtu); return -1; } want = s->rxlen - (s->p - s->buf); if ((got = readn(s->fd, s->p, want)) != want){ werrstr("media: short payload read (%d < %d)", got, want); return -1; } return s->rxlen; } int ncpcall(Session *s) { int err; ushort msg; int len = (s->p - s->buf); s->buf[4] = len >> 24; s->buf[5] = len >> 16; s->buf[6] = len >> 8; s->buf[7] = len; if (s->type == Tvarlen){ s->buf[23] = (len-26) >> 8; s->buf[24] = (len-26); } if (s->buf[16] != 0x22 || s->buf[17] != 0x22){ fprint(2, "ncpcall() called before ncphdr()\n"); abort(); } if (Debug) fprint(2, "TX %N", s->buf); if (write(s->fd, s->buf, s->p - s->buf) == -1){ werrstr("media: write failed"); return -1; } if (getpkt(s) == -1) return -1; if (Debug) fprint(2, "RX %N", s->buf); /* * NB: signature and packet length * already parsed and checked */ msg = gb16(s); switch(msg){ case Mreply: break; case Mdisconnected: /* experience tells us this */ sysfatal("disconnected"); return -1; default: werrstr("0x%04x - unexpected packet type", msg); return -1; } if (g8(s) != s->seq){ werrstr("incorrect sequence number"); return -1; } s->seq = (s->seq +1) % 256; if (g8(s) != (s->conn & 0xff)){ werrstr("bad connection # LSB"); return -1; } if (g8(s) != s->task){ werrstr("unexpected task #"); return -1; } if (g8(s) != ((s->conn >> 8) & 0xff)){ werrstr("bad connection # MSB"); return -1; } if ((err = g8(s)) != 0){ werrstr("%s", nwerrstr(err)); return -1; } if ((err = g8(s)) != 0){ if (err & (1 << 6)) fprint(2, "broadcast message waiting"); else{ if (err & (1 << 0)) werrstr("bad service connection"); if (err & (1 << 2)) werrstr("no connections avaliable"); if (err & (1 << 4)) werrstr("server is down"); return -1; } } return 0; } void pmem(Session *s, void *v, int len) { uchar *str = v; while(len--) *s->p++ = *str++; } void pstr(Session *s, char *str) { *s->p++ = strlen(str); while(*str) *s->p++ = *str++; } void pb32(Session *s, uint n) { *(s->p++) = (n >> 24) & 0xff; *(s->p++) = (n >> 16) & 0xff; *(s->p++) = (n >> 8) & 0xff; *(s->p++) = n & 0xff; } void pl32(Session *s, uint n) { *(s->p++) = n & 0xff; *(s->p++) = (n >> 8) & 0xff; *(s->p++) = (n >> 16) & 0xff; *(s->p++) = (n >> 24) & 0xff; } void pb16(Session *s, ushort n) { *(s->p++) = (n >> 8) & 0xff; *(s->p++) = n & 0xff; } void pl16(Session *s, ushort n) { *(s->p++) = n & 0xff; *(s->p++) = (n >> 8) & 0xff; } void p8(Session *s, uchar n) { *(s->p++) = n & 0xff; } /* * get & translate 32bit file descriptor * into a 48 bit file handle */ void gfhand32(Session *s, Fh fh) { uchar *p = fh; long n = gb32(s); *p++ = ((n+1) >> 8) & 0xff; *p++ = (n+1) & 0xff; *p++ = (n >> 24) & 0xff; *p++ = (n >> 16) & 0xff; *p++ = (n >> 8) & 0xff; *p++ = n & 0xff; USED(p); } void ginfo(Session *s, FInfo *fi) { gl32(s); // data space allocated - in 4k blocks fi->attr = gl32(s); fi->flags = gl16(s); fi->size = gl32(s); gl32(s); // total space allocated - in 4k blocks gl16(s); // number of data streams fi->created = gdatetime(s); fi->creator = gb32(s); fi->modified = gdatetime(s); fi->modifier = gb32(s); fi->accessed = gdate(s); fi->archived = gdatetime(s); fi->archiver = gb32(s); fi->rights = gl16(s); fi->dirent = gl32(s); fi->dosdir = gl32(s); fi->vol = gl32(s); gl32(s); // extended attributes gl32(s); // extended attributes gl32(s); // extended attributes fi->creatns = gl32(s); gstr(s, fi->name, PATHLEN); } /* * Convert Unix style path to a NetwareHandlePathStruct */ void phps(Session *s, char *str) { uchar *noc; // num of components uchar *ccl; // current component length if (*str == '/') // should always be absolute paths str++; p8(s, 0); // volume number (none) pl32(s, 0); // directory base / handle (none) p8(s, 0xff); // flags (no handles present) noc = s->p++; // path component count *noc = 0; for(ccl = s->p++ ; ; str++, s->p++){ if (! *str){ *ccl = (s->p - ccl) -1; (*noc)++; break; } if (*str == '/'){ *ccl = (s->p - ccl) -1; ccl = s->p; (*noc)++; } *s->p = *str; } } /* * Special, two path version of PathHandleStruct used only by * Rename Or Move a File or Subdirectory, * appearently to save space (though it doesn't). */ void pphs2(Session *s, char *s1, char *s2) { int i; uchar *noc[2]; // num of components uchar *ccl; // current component length char *str[2] = {s1, s2}; if (*str[0] == '/') // should always be absolute paths str[0]++; p8(s, 0); // volume number (none) pl32(s, 0); // directory base / handle (none) p8(s, 0xff); // flags (no handles present) noc[0] = s->p++; // path component count *noc[0] = 0; if (*str[1] == '/') // should always be absolute paths str[1]++; p8(s, 0); // volume number (none) pl32(s, 0); // directory base / handle (none) p8(s, 0xff); // flags (no handles present) noc[1] = s->p++; // path component count *noc[1] = 0; for (i = 0; i < 2; i++){ for(ccl = s->p++ ; ; str[i]++, s->p++){ if (! *str[i]){ *ccl = (s->p - ccl) -1; (*noc[i])++; break; } if (*str[i] == '/'){ *ccl = (s->p - ccl) -1; ccl = s->p; (*noc[i])++; } *s->p = *str[i]; } } } void gmem(Session *s, void *v, int len) { uchar *str = v; while(len--) *str++ = *s->p++; } void gstr(Session *s, char *str, int maxlen) { int len; char *eos; len = *s->p++; if (len > maxlen) len = maxlen; eos = str + len; while(len--) *str++ = *s->p++; *eos = 0; } uint gb32(Session *s) { uint n; n = *s->p++ << 24; n |= *s->p++ << 16; n |= *s->p++ << 8; n |= *s->p++; return n; } uint gl32(Session *s) { uint n; n = *s->p++; n |= *s->p++ << 8; n |= *s->p++ << 16; n |= *s->p++ << 24; return n; } ushort gb16(Session *s) { ushort n; n = *s->p++ << 8; n |= *s->p++; return n; } ushort gl16(Session *s) { ushort n; n = *s->p++; n |= *s->p++ << 8; return n; } uchar g8(Session *s) { return *s->p++; } void pdatetime(Session *s, long utc) { Tm *tm = localtime(utc); pl16(s, tm->mday | ((tm->mon +1) << 5) | ((tm->year -80) << 9)); pl16(s, (tm->hour << 11) | (tm->min << 5) | (tm->sec >> 1)); } void pdate(Session *s, long utc) { Tm *tm = localtime(utc); pl16(s, tm->mday | ((tm->mon +1) << 5) | ((tm->year -80) << 9)); } /* * get a packed date and time */ long gdatetime(Session *s) { int ti = gl16(s); int da = gl16(s); Tm *tm = localtime(time(nil)); tm->year = (da >> 9) + 80; tm->mon = ((da >> 5) & 0xf) - 1; tm->mday = da & 0x1f; tm->hour = ti >> 11; tm->min = (ti >> 5) & 0x3f; tm->sec = (ti << 1) & 0x3f; return tm2sec(tm); } /* * get a packed date only */ long gdate(Session *s) { int da = gl16(s); Tm *tm = localtime(time(nil)); tm->hour = 0; tm->min = 0; tm->sec = 0; tm->year = (da >> 9) +80; tm->mon = ((da >> 5) & 0xf) -1; tm->mday = da & 0x1f; return tm2sec(tm); } long gtbuf(Session *s) { Tm *tm; tm = localtime(time(nil)); tm->year = *(s->p++); tm->mon = *(s->p++) -1; tm->mday = *(s->p++); tm->hour = *(s->p++); tm->min = *(s->p++); tm->sec = *(s->p++); return tm2sec(tm); } char * strupr(char *s) { char *p; for(p = s; *p; p++) if (islower(*p)) *p = toupper(*p); return s; } char * strlwr(char *s) { char *p; for(p = s; *p; p++) if (isupper(*p)) *p = tolower(*p); return s; }