/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <fcall.h>#include <thread.h>#include <9p.h>#include "cifs.h"#include "remsmb.h"#include "apinums.h" static Pkt *thdr(Session *s, Share *sp){ Pkt *p; p = cifshdr(s, sp, SMB_COM_TRANSACTION); p->tbase = pl16(p, 0); /* 0 Total parameter bytes to be sent, filled later */ pl16(p, 0); /* 2 Total data bytes to be sent, filled later */ pl16(p, 64); /* 4 Max parameter to return */ pl16(p, MTU - T2HDRLEN - 128); /* 6 Max data to return */ pl16(p, 1); /* 8 Max setup count to return */ pl16(p, 0); /* 10 Flags */ pl32(p, 1000); /* 12 Timeout (ms) */ pl16(p, 0); /* 16 Reserved */ pl16(p, 0); /* 18 Parameter count, filled later */ pl16(p, 0); /* 20 Parameter offset, filled later */ pl16(p, 0); /* 22 Data count, filled later */ pl16(p, 0); /* 24 Data offset, filled later */ pl16(p, 0); /* 26 Setup count (in words) */ pbytes(p); /* end of cifs words section */ return p;} static voidptparam(Pkt *p){ uchar *pos; if(((p->pos - p->tbase) % 2) != 0) p8(p, 0); /* pad to word boundry */ pos = p->pos; p->pos = p->tbase + 20; pl16(p, pos - p->buf - NBHDRLEN); /* param offset */ p->tparam = p->pos = pos;} static voidptdata(Pkt *p){ uchar *pos = p->pos; assert(p->tparam != 0); if(((p->pos - p->tbase) % 2) != 0) p8(p, 0); /* pad to word boundry */ p->pos = p->tbase + 0; pl16(p, pos - p->tparam); /* total param count */ p->pos = p->tbase + 18; pl16(p, pos - p->tparam); /* param count */ p->pos = p->tbase + 24; pl16(p, pos - p->buf - NBHDRLEN); /* data offset */ p->tdata = p->pos = pos;} static inttrpc(Pkt *p){ int got; uchar *pos = p->pos; assert(p->tbase != 0); assert(p->tdata != 0); p->pos = p->tbase + 2; pl16(p, pos - p->tdata); /* total data count */ p->pos = p->tbase + 22; pl16(p, pos - p->tdata); /* data count */ p->pos = pos; if((got = cifsrpc(p)) == -1) return -1; gl16(p); /* Total parameter count */ gl16(p); /* Total data count */ gl16(p); /* Reserved */ gl16(p); /* Parameter count in this buffer */ p->tparam = p->buf + NBHDRLEN + gl16(p); /* Parameter offset */ gl16(p); /* Parameter displacement */ gl16(p); /* Data count (this buffer); */ p->tdata = p->buf + NBHDRLEN + gl16(p); /* Data offset */ gl16(p); /* Data displacement */ g8(p); /* Setup count */ g8(p); /* Reserved */ return got;} static voidgtparam(Pkt *p){ p->pos = p->tparam;} static voidgtdata(Pkt *p){ p->pos = p->tdata;} intRAPshareenum(Session *s, Share *sp, Share **ent){ int ngot = 0, err, navail, nret; char tmp[1024]; Pkt *p; Share *q; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WShareEnum); pascii(p, REMSmb_NetShareEnum_P); /* request descriptor */ pascii(p, REMSmb_share_info_0); /* reply descriptor */ pl16(p, 0); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ gl16(p); /* rx buffer offset */ nret = gl16(p); /* number of entries returned */ navail = gl16(p); /* number of entries available */ if(err && err != RAP_ERR_MOREINFO){ werrstr("%s", raperrstr(err)); free(p); return -1; } if(ngot == 0){ *ent = emalloc9p(sizeof(Share) * navail); memset(*ent, 0, sizeof(Share) * navail); } q = *ent + ngot; for (; ngot < navail && nret--; ngot++){ gmem(p, tmp, 13); /* name */ tmp[13] = 0; q->name = estrdup9p(tmp); q++; } if(ngot < navail) fprint(2, "%s: %d/%d - share list incomplete\n", argv0, ngot, navail); free(p); return ngot;} intRAPshareinfo(Session *s, Share *sp, char *share, Shareinfo2 *si2p){ int conv, err; char tmp[1024]; Pkt *p; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WShareGetInfo); pascii(p, REMSmb_NetShareGetInfo_P); /* request descriptor */ pascii(p, REMSmb_share_info_2); /* reply descriptor */ pascii(p, share); pl16(p, 1); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ conv = gl16(p); /* rx buffer offset */ gl16(p); /* number of entries returned */ gl16(p); /* number of entries available */ if(err){ werrstr("%s", raperrstr(err)); free(p); return -1; } memset(si2p, 0, sizeof(Shareinfo2)); gmem(p, tmp, 13); tmp[13] = 0; g8(p); /* padding */ si2p->name = estrdup9p(tmp); si2p->type = gl16(p); gconv(p, conv, tmp, sizeof tmp); si2p->comment = estrdup9p(tmp); gl16(p); /* comment offset high (unused) */ si2p->perms = gl16(p); si2p->maxusrs = gl16(p); si2p->activeusrs = gl16(p); gconv(p, conv, tmp, sizeof tmp); si2p->path = estrdup9p(tmp); gl16(p); /* path offset high (unused) */ gmem(p, tmp, 9); tmp[9] = 0; si2p->passwd = estrdup9p(tmp); free(p); return 0;} /* * Tried to split sessionenum into two passes, one getting the names * of the connected workstations and the other collecting the detailed info, * however API_WSessionGetInfo doesn't seem to work agains win2k3 for infolevel * ten and infolevel one and two are priviledged calls. This means this code * will work for small numbers of sessions agains win2k3 and fail for samba 3.0 * as it supports info levels zero and two only. */intRAPsessionenum(Session *s, Share *sp, Sessinfo **sip){ int ngot = 0, conv, err, navail, nret; char tmp[1024]; Pkt *p; Sessinfo *q; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WSessionEnum); pascii(p, REMSmb_NetSessionEnum_P); /* request descriptor */ pascii(p, REMSmb_session_info_10); /* reply descriptor */ pl16(p, 10); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ conv = gl16(p); /* rx buffer offset */ nret = gl16(p); /* number of entries returned */ navail = gl16(p); /* number of entries available */ if(err && err != RAP_ERR_MOREINFO){ werrstr("%s", raperrstr(err)); free(p); return -1; } if(ngot == 0){ *sip = emalloc9p(sizeof(Sessinfo) * navail); memset(*sip, 0, sizeof(Sessinfo) * navail); } q = *sip + ngot; while(nret-- != 0){ gconv(p, conv, tmp, sizeof tmp); q->wrkstn = estrdup9p(tmp); gconv(p, conv, tmp, sizeof tmp); q->user = estrdup9p(tmp); q->sesstime = gl32(p); q->idletime = gl32(p); ngot++; q++; } if(ngot < navail) fprint(2, "warning: %d/%d - session list incomplete\n", ngot, navail); free(p); return ngot;} intRAPgroupenum(Session *s, Share *sp, Namelist **nlp){ int ngot, err, navail, nret; char tmp[1024]; Pkt *p; Namelist *q; ngot = 0; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WGroupEnum); pascii(p, REMSmb_NetGroupEnum_P); /* request descriptor */ pascii(p, REMSmb_group_info_0); /* reply descriptor */ pl16(p, 0); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ gl16(p); /* rx buffer offset */ nret = gl16(p); /* number of entries returned */ navail = gl16(p); /* number of entries available */ if(err && err != RAP_ERR_MOREINFO){ werrstr("%s", raperrstr(err)); free(p); return -1; } *nlp = emalloc9p(sizeof(Namelist) * navail); memset(*nlp, 0, sizeof(Namelist) * navail); q = *nlp + ngot; while(ngot < navail && nret--){ gmem(p, tmp, 21); tmp[21] = 0; q->name = estrdup9p(tmp); ngot++; q++; if(p->pos >= p->eop) /* Windows seems to lie somtimes */ break; } free(p); return ngot;} intRAPgroupusers(Session *s, Share *sp, char *group, Namelist **nlp){ int ngot, err, navail, nret; char tmp[1024]; Pkt *p; Namelist *q; ngot = 0; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WGroupGetUsers); pascii(p, REMSmb_NetGroupGetUsers_P); /* request descriptor */ pascii(p, REMSmb_user_info_0); /* reply descriptor */ pascii(p, group); /* group name for list */ pl16(p, 0); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ gl16(p); /* rx buffer offset */ nret = gl16(p); /* number of entries returned */ navail = gl16(p); /* number of entries available */ if(err && err != RAP_ERR_MOREINFO){ werrstr("%s", raperrstr(err)); free(p); return -1; } *nlp = emalloc9p(sizeof(Namelist) * navail); memset(*nlp, 0, sizeof(Namelist) * navail); q = *nlp + ngot; while(ngot < navail && nret--){ gmem(p, tmp, 21); tmp[21] = 0; q->name = estrdup9p(tmp); ngot++; q++; if(p->pos >= p->eop) /* Windows seems to lie somtimes */ break; } free(p); return ngot;} intRAPuserenum(Session *s, Share *sp, Namelist **nlp){ int ngot, err, navail, nret; char tmp[1024]; Pkt *p; Namelist *q; ngot = 0; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WUserEnum); pascii(p, REMSmb_NetUserEnum_P); /* request descriptor */ pascii(p, REMSmb_user_info_0); /* reply descriptor */ pl16(p, 0); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ gl16(p); /* rx buffer offset */ nret = gl16(p); /* number of entries returned */ navail = gl16(p); /* number of entries available */ if(err && err != RAP_ERR_MOREINFO){ werrstr("%s", raperrstr(err)); free(p); return -1; } *nlp = emalloc9p(sizeof(Namelist) * navail); memset(*nlp, 0, sizeof(Namelist) * navail); q = *nlp + ngot; while(ngot < navail && nret--){ gmem(p, tmp, 21); tmp[21] = 0; q->name = estrdup9p(tmp); ngot++; q++; if(p->pos >= p->eop) /* Windows seems to lie somtimes */ break; } free(p); return ngot;} intRAPuserenum2(Session *s, Share *sp, Namelist **nlp){ int ngot, resume, err, navail, nret; char tmp[1024]; Pkt *p; Namelist *q; ngot = 0; resume = 0;more: p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WUserEnum2); pascii(p, REMSmb_NetUserEnum2_P); /* request descriptor */ pascii(p, REMSmb_user_info_0); /* reply descriptor */ pl16(p, 0); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ pl32(p, resume); /* resume key to allow multiple fetches */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */Lines 1–500 of 794. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h> #include <libc.h> #include <fcall.h> #include <thread.h> #include <9p.h> #include "cifs.h" #include "remsmb.h" #include "apinums.h" static Pkt * thdr(Session *s, Share *sp) { Pkt *p; p = cifshdr(s, sp, SMB_COM_TRANSACTION); p->tbase = pl16(p, 0); /* 0 Total parameter bytes to be sent, filled later */ pl16(p, 0); /* 2 Total data bytes to be sent, filled later */ pl16(p, 64); /* 4 Max parameter to return */ pl16(p, MTU - T2HDRLEN - 128); /* 6 Max data to return */ pl16(p, 1); /* 8 Max setup count to return */ pl16(p, 0); /* 10 Flags */ pl32(p, 1000); /* 12 Timeout (ms) */ pl16(p, 0); /* 16 Reserved */ pl16(p, 0); /* 18 Parameter count, filled later */ pl16(p, 0); /* 20 Parameter offset, filled later */ pl16(p, 0); /* 22 Data count, filled later */ pl16(p, 0); /* 24 Data offset, filled later */ pl16(p, 0); /* 26 Setup count (in words) */ pbytes(p); /* end of cifs words section */ return p; } static void ptparam(Pkt *p) { uchar *pos; if(((p->pos - p->tbase) % 2) != 0) p8(p, 0); /* pad to word boundry */ pos = p->pos; p->pos = p->tbase + 20; pl16(p, pos - p->buf - NBHDRLEN); /* param offset */ p->tparam = p->pos = pos; } static void ptdata(Pkt *p) { uchar *pos = p->pos; assert(p->tparam != 0); if(((p->pos - p->tbase) % 2) != 0) p8(p, 0); /* pad to word boundry */ p->pos = p->tbase + 0; pl16(p, pos - p->tparam); /* total param count */ p->pos = p->tbase + 18; pl16(p, pos - p->tparam); /* param count */ p->pos = p->tbase + 24; pl16(p, pos - p->buf - NBHDRLEN); /* data offset */ p->tdata = p->pos = pos; } static int trpc(Pkt *p) { int got; uchar *pos = p->pos; assert(p->tbase != 0); assert(p->tdata != 0); p->pos = p->tbase + 2; pl16(p, pos - p->tdata); /* total data count */ p->pos = p->tbase + 22; pl16(p, pos - p->tdata); /* data count */ p->pos = pos; if((got = cifsrpc(p)) == -1) return -1; gl16(p); /* Total parameter count */ gl16(p); /* Total data count */ gl16(p); /* Reserved */ gl16(p); /* Parameter count in this buffer */ p->tparam = p->buf + NBHDRLEN + gl16(p); /* Parameter offset */ gl16(p); /* Parameter displacement */ gl16(p); /* Data count (this buffer); */ p->tdata = p->buf + NBHDRLEN + gl16(p); /* Data offset */ gl16(p); /* Data displacement */ g8(p); /* Setup count */ g8(p); /* Reserved */ return got; } static void gtparam(Pkt *p) { p->pos = p->tparam; } static void gtdata(Pkt *p) { p->pos = p->tdata; } int RAPshareenum(Session *s, Share *sp, Share **ent) { int ngot = 0, err, navail, nret; char tmp[1024]; Pkt *p; Share *q; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WShareEnum); pascii(p, REMSmb_NetShareEnum_P); /* request descriptor */ pascii(p, REMSmb_share_info_0); /* reply descriptor */ pl16(p, 0); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ gl16(p); /* rx buffer offset */ nret = gl16(p); /* number of entries returned */ navail = gl16(p); /* number of entries available */ if(err && err != RAP_ERR_MOREINFO){ werrstr("%s", raperrstr(err)); free(p); return -1; } if(ngot == 0){ *ent = emalloc9p(sizeof(Share) * navail); memset(*ent, 0, sizeof(Share) * navail); } q = *ent + ngot; for (; ngot < navail && nret--; ngot++){ gmem(p, tmp, 13); /* name */ tmp[13] = 0; q->name = estrdup9p(tmp); q++; } if(ngot < navail) fprint(2, "%s: %d/%d - share list incomplete\n", argv0, ngot, navail); free(p); return ngot; } int RAPshareinfo(Session *s, Share *sp, char *share, Shareinfo2 *si2p) { int conv, err; char tmp[1024]; Pkt *p; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WShareGetInfo); pascii(p, REMSmb_NetShareGetInfo_P); /* request descriptor */ pascii(p, REMSmb_share_info_2); /* reply descriptor */ pascii(p, share); pl16(p, 1); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ conv = gl16(p); /* rx buffer offset */ gl16(p); /* number of entries returned */ gl16(p); /* number of entries available */ if(err){ werrstr("%s", raperrstr(err)); free(p); return -1; } memset(si2p, 0, sizeof(Shareinfo2)); gmem(p, tmp, 13); tmp[13] = 0; g8(p); /* padding */ si2p->name = estrdup9p(tmp); si2p->type = gl16(p); gconv(p, conv, tmp, sizeof tmp); si2p->comment = estrdup9p(tmp); gl16(p); /* comment offset high (unused) */ si2p->perms = gl16(p); si2p->maxusrs = gl16(p); si2p->activeusrs = gl16(p); gconv(p, conv, tmp, sizeof tmp); si2p->path = estrdup9p(tmp); gl16(p); /* path offset high (unused) */ gmem(p, tmp, 9); tmp[9] = 0; si2p->passwd = estrdup9p(tmp); free(p); return 0; } /* * Tried to split sessionenum into two passes, one getting the names * of the connected workstations and the other collecting the detailed info, * however API_WSessionGetInfo doesn't seem to work agains win2k3 for infolevel * ten and infolevel one and two are priviledged calls. This means this code * will work for small numbers of sessions agains win2k3 and fail for samba 3.0 * as it supports info levels zero and two only. */ int RAPsessionenum(Session *s, Share *sp, Sessinfo **sip) { int ngot = 0, conv, err, navail, nret; char tmp[1024]; Pkt *p; Sessinfo *q; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WSessionEnum); pascii(p, REMSmb_NetSessionEnum_P); /* request descriptor */ pascii(p, REMSmb_session_info_10); /* reply descriptor */ pl16(p, 10); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ conv = gl16(p); /* rx buffer offset */ nret = gl16(p); /* number of entries returned */ navail = gl16(p); /* number of entries available */ if(err && err != RAP_ERR_MOREINFO){ werrstr("%s", raperrstr(err)); free(p); return -1; } if(ngot == 0){ *sip = emalloc9p(sizeof(Sessinfo) * navail); memset(*sip, 0, sizeof(Sessinfo) * navail); } q = *sip + ngot; while(nret-- != 0){ gconv(p, conv, tmp, sizeof tmp); q->wrkstn = estrdup9p(tmp); gconv(p, conv, tmp, sizeof tmp); q->user = estrdup9p(tmp); q->sesstime = gl32(p); q->idletime = gl32(p); ngot++; q++; } if(ngot < navail) fprint(2, "warning: %d/%d - session list incomplete\n", ngot, navail); free(p); return ngot; } int RAPgroupenum(Session *s, Share *sp, Namelist **nlp) { int ngot, err, navail, nret; char tmp[1024]; Pkt *p; Namelist *q; ngot = 0; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WGroupEnum); pascii(p, REMSmb_NetGroupEnum_P); /* request descriptor */ pascii(p, REMSmb_group_info_0); /* reply descriptor */ pl16(p, 0); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ gl16(p); /* rx buffer offset */ nret = gl16(p); /* number of entries returned */ navail = gl16(p); /* number of entries available */ if(err && err != RAP_ERR_MOREINFO){ werrstr("%s", raperrstr(err)); free(p); return -1; } *nlp = emalloc9p(sizeof(Namelist) * navail); memset(*nlp, 0, sizeof(Namelist) * navail); q = *nlp + ngot; while(ngot < navail && nret--){ gmem(p, tmp, 21); tmp[21] = 0; q->name = estrdup9p(tmp); ngot++; q++; if(p->pos >= p->eop) /* Windows seems to lie somtimes */ break; } free(p); return ngot; } int RAPgroupusers(Session *s, Share *sp, char *group, Namelist **nlp) { int ngot, err, navail, nret; char tmp[1024]; Pkt *p; Namelist *q; ngot = 0; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WGroupGetUsers); pascii(p, REMSmb_NetGroupGetUsers_P); /* request descriptor */ pascii(p, REMSmb_user_info_0); /* reply descriptor */ pascii(p, group); /* group name for list */ pl16(p, 0); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ gl16(p); /* rx buffer offset */ nret = gl16(p); /* number of entries returned */ navail = gl16(p); /* number of entries available */ if(err && err != RAP_ERR_MOREINFO){ werrstr("%s", raperrstr(err)); free(p); return -1; } *nlp = emalloc9p(sizeof(Namelist) * navail); memset(*nlp, 0, sizeof(Namelist) * navail); q = *nlp + ngot; while(ngot < navail && nret--){ gmem(p, tmp, 21); tmp[21] = 0; q->name = estrdup9p(tmp); ngot++; q++; if(p->pos >= p->eop) /* Windows seems to lie somtimes */ break; } free(p); return ngot; } int RAPuserenum(Session *s, Share *sp, Namelist **nlp) { int ngot, err, navail, nret; char tmp[1024]; Pkt *p; Namelist *q; ngot = 0; p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WUserEnum); pascii(p, REMSmb_NetUserEnum_P); /* request descriptor */ pascii(p, REMSmb_user_info_0); /* reply descriptor */ pl16(p, 0); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */ gl16(p); /* rx buffer offset */ nret = gl16(p); /* number of entries returned */ navail = gl16(p); /* number of entries available */ if(err && err != RAP_ERR_MOREINFO){ werrstr("%s", raperrstr(err)); free(p); return -1; } *nlp = emalloc9p(sizeof(Namelist) * navail); memset(*nlp, 0, sizeof(Namelist) * navail); q = *nlp + ngot; while(ngot < navail && nret--){ gmem(p, tmp, 21); tmp[21] = 0; q->name = estrdup9p(tmp); ngot++; q++; if(p->pos >= p->eop) /* Windows seems to lie somtimes */ break; } free(p); return ngot; } int RAPuserenum2(Session *s, Share *sp, Namelist **nlp) { int ngot, resume, err, navail, nret; char tmp[1024]; Pkt *p; Namelist *q; ngot = 0; resume = 0; more: p = thdr(s, sp); pstr(p, "\\PIPE\\LANMAN"); ptparam(p); pl16(p, API_WUserEnum2); pascii(p, REMSmb_NetUserEnum2_P); /* request descriptor */ pascii(p, REMSmb_user_info_0); /* reply descriptor */ pl16(p, 0); /* detail level */ pl16(p, MTU - 200); /* receive buffer length */ pl32(p, resume); /* resume key to allow multiple fetches */ ptdata(p); if(trpc(p) == -1){ free(p); return -1; } gtparam(p); err = gl16(p); /* error code */