From f6e0a67e7800929e761422689a8adb05660d4487 Mon Sep 17 00:00:00 2001 From: ncpfs archive import Date: Tue, 28 Apr 2026 20:39:57 +0200 Subject: [PATCH] Import ncpfs 0.2 --- .downloads/ncpfs-0.2.tgz | Bin 0 -> 44900 bytes Changes | 6 + Makefile | 17 +- README | 121 +++------ dir.c | 227 +++++++++++++++-- file.c | 83 +++++- inode.c | 55 +++- ipx.tar | Bin 0 -> 40960 bytes ncp.h | 34 +-- ncp_fs.h | 7 +- ncpfs-0.1.lsm => ncpfs-0.2.lsm | 10 +- ncplib.c | 237 ++++++++++++++++- ncplib.h | 44 +++- ncpmount.c | 450 +++++++++++++++++++++++++++++---- ncptest.c | 173 +++++++++++++ nwcrypt.c | 75 +++++- start_ipx | 7 + startnet | 3 - 18 files changed, 1350 insertions(+), 199 deletions(-) create mode 100644 .downloads/ncpfs-0.2.tgz create mode 100644 Changes create mode 100644 ipx.tar rename ncpfs-0.1.lsm => ncpfs-0.2.lsm (61%) create mode 100644 ncptest.c create mode 100755 start_ipx delete mode 100755 startnet diff --git a/.downloads/ncpfs-0.2.tgz b/.downloads/ncpfs-0.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..0bce85f8d195b22e04ad7f51e602bdcc680054ea GIT binary patch literal 44900 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 z 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%0D*61>Z@o3~bywSui8jKzJcuyqncMYs2Gb`4c z@b~d!iBvrkGR<&FeC{TbPmL`>?QT6TrB3N$+?>OZ#ycpmNC?~Wm?CX5cUm}Vf zNLM5aD@y@_wXi4E0rWsItN3lwdI8KfEwgK@5uT}VoIQ>cCOd$Csgo$fL!!_gJ`t5oHy#U_jR@+YS z=Z{kL8k@2nV(9+RCwu;b|E|?*&Dtm$f9?4HVtX@*|G!yZ$Mc`{#{K!vSNS~0aNX<9 zxgU?boy3wu1mXP1783m&2*hcjG07XO4amv?bM>Miy{JF+$p%Ul$&$baB`VM` zN6&p9j>tbx8By5sS`aZwZss}dfb)ZQizh>og3L%$B?I|Fhsu;2@X3R-Pd1TckVVF@ za>|-kabCMVStViEz1y9;)I6Q~V|RMH7Ws@V3XGZ5*m*LU^?3E=Mceq_jg4!OtWC_5 zlUGVK%u=v|9gNxP2bXJ;aOC#^Vl;@if`L=C{t2uvMq`a;eS3Smc>M!m;rd_S-q_l1 zHYomY6Z3yGYxnE_>+pYn@?i#2vv&1+y*Bd%X7Hwf;Y! zaWiz#i^uO%7cU<3p`FSDv#Uh|TBI>cU=K5f_+*NGf;na|tn@84v2O^64MHg$ve7T~8QUboH;UO}Dx=k25R`Oh#6@uGcx z-0F11i<2|4FHZN*&f5nUNBd{u^y2LFq|>Si(cxq))WRGz4{55Vo;v)OL&rP-^6Y_* z+?1O>dGk+h7tbHH;!^AzZG~63+{NQdI(}Bi*V&n+`pN88MLX!%s$y$rVe5K}>dh)*&*i&VU{xnxu^%&zfWnQx#3tpeX z-=Z@Es*WK(5CZJHd(=9{%^zKHqNpC|G)ZAV%CfAG*`w1%I1oyi0Ya59TLxKQS%M@e zUPz`$gcpFyIRU^|1x6XEBsR)!*AHNty>6H7eAosjZLz@}P%?4#E1LGnF2fm;%lr}^ zQVER$-s%74vt;1Y`#;Vf^n1vEQ2Lr`|F^lZwa)UtaWDVBV*UpsX=_p1hrDbKIf)yh zc;Kf}Bjm9_4zOWAo7|+*FkDVk83$mGmz!b%pHEy62ANC)K4u$8XH3BK2fdt@Gnp9h zDc-lWpUwgh-GiKxcsQGV%$a-P@sm|yzd@0upOc&-r)D1qn4a1JW-ZH%nTg4IJPzWb zgcbz}CknGl+&v9N7M>NEaP4Zvc&7J3E1HqBK@@cj4x(l~re?d8IZuiu2l;51>=7P% zl`em?B&pNI{9j@i;h)`18Gftm9#n+wx1M9xBE~ zJd$$5@=9N)NE${It;N3KDUS-|5kb0N6&^+REjyC;u2sH;l~sa)LD0Ie8Uq!H{cs)UIwaVRVFrRII` z%*y5g*)As05YVyqH$Y!f?igG=6eu*f(Y)P%x&w{j)Bnjr|q=zBy~3w~{vrN)%aQzq%V^GBN)h^ol`D^WE(h= zHv?TE8F|`%Jd}t4Sq?%U(DqFv#u#g%=czQaxMPDx#54>!9GL1hC&IJ$0mM$jzM+O2 zn#haG4-p$QH`%Ma3C{Rj5P?TTBNu4$j2YrqjkobGi7!EC!s)@xI5Y*0DM@pi9z#M5 zunTo(qnJF-L#mZm+6H6=%B)ECBCou|{FaSEz}KRf_}N-xsVOi7FnT8QfeH8bO{BzP zQGjk?^$aMch)reE=qk(3m<}sPZ4G^jWr32(YW$>oc6f4p^fSz9C4JxDsHw)CGd~A< zq;#Rg7+uN2bKXFbh!fJ;K?bO0N0L2sBl&I<{!!iz2DS0w6AMl$H?;sa-gVL3)a4{q znzi^<3^2?RP7@AP08^=9W& z_WuWbOW^m(|1O#v4SoK*y-E4sH#YC{KYqRQpS60eA=aKHhlq}|mN<)3#1$Y{j=hfN z*UNri-aEld4x(AxuGOIiUlejqm7GRuzAn1s<9N8=z{Y?SxOirQ^Xy;n5l&zBt9Vh?YB* zaYPF*eo^}7h?A$s@{%r{Dd8Os<0uiz_MrPQzVyAw(HA#I^5{xk!{e)IeH9Pc*ZIro za-27)Icmdp3hZqRJQ4M6PBl+0Me-C3V@RpdyL2Qb&o=OY3NQ9i*h)M)bnq;65K@G} z=!(h*19@`~0H_J^{FY)>O$UiD`)EOLxeMVE;fV;Y!xp@BPd3;JauPc1#D45sQ zpa@?;oXLxzdN}I%mXgimwcwcIOk);xI_7kWPGKi_CQ0{%2|x1O&pxV4DCJRPU@)N3 z;NdDu9(9s>a}`GFz7yV490MIdNr!{j686d+yyC~zim1{WTt9q|K2CU0tdM=gN8&{X zpSVu~VOOgNo%9?Bdn*_iLcN4Is^SGIIvIU~x2JCau@ld|Mr>Gz;#GWw5KX-ysJwDZ zA}6qlH0gly*~j?1C(wL8WKo9p%sJ(=Ye&Z@G^oQ^JG^8v@WJ+sX=i%r$t#zbULDj@ z3<~J;-QXKPx~f!@E0^-<*Ss-@N6?5c46f&F(xC;A91;eW`zUvNnB1n#FV`2 zOU(l^dj7z;pf~UWTI#YBZV3TLl8&zVRfw}P^|WsTm#R7ET*vA~U7aI#=S}I#EC;-n z7o>g3hp=VFsFORRCMMCRLCqUGT;TdaRN%d5?*rKbtExn9b9_-&p&YMUd${Zz_!av! zV&WNM=y`m}oD2Fw`OM-I<;hvJh@5@>6SM3LWUj$Z2}qsiPmS(k|8{x%|5L*8H_2g@)2| zc{Nkdsx@cqVLmMBif6pRHn3d))qhVBC>S9Od@|sXd$Yr9+9z0G%tnO3iaY78ZuLdB!^vQv80vF;>f2Z4-ynwSES-1w;VdtS&%`!uM>BWrh};= zSYxBsfR85WDr6PMP}ai$)$Jj5h;vIafY_)XlSC95LUUBlWsILP@hFH2PC9Tb1dd`^ z5#xe!=0IGjId53O5t_&_Y!SB=VJ}MV=s^xbk0n8)#!8HPyUd1F>1wi>N0F(=;Pjfx zwNFkVv_i%p1!m)F5;;OE{fL^0-=BrEXvDn(&mmq8v^inMA@BSsjzuq`ke4Ava!8tXunZ}Y z$^Ot#1Z>nl}zDX%Irm6%-JMijDw>6#a_+OBa=tl-_sR%~}+ zsq<;|$k4w~=zdT;bEPyB1XcG~j zn>FwS$dM~cZf$|5bEwjAL~ls}o5o3Sa(ouCsKarkSfHF(YJ=*L+8qw7Dr&sel*p}& zdT|j8ik?wK(Q5Rk1KkP|P?08}L_ZI|Us0;NM!gdB0niocm3R)owi((Tpm}PF85-XM zpOJ$HMhgtq*b_1;kw)nyr89uG6&F@fnfOXT(jX~`(w&}dOw$2K+9`4i+8A=6Rm2)h z3MS0~>@htBK{x~Mf<{0oggM}l$?-%k$8)Ix`Jj03Q%0S3gm(v|2Bzslt^$TbSEwWg z3$m`!inlIE5C@Xjrs+}_8>|H*#i%zLDfxxX3EJ$2;=S+Pq$`jfTqRsOA7*qb5++kx18+z{qDSL13Z0%1q4SK>C_SMnm|=%%8FehFeTER;z&K zuIwgMcFaZvvdKwlqUn|TOqK_2Mjan@0eDZRUXdpaFX2!{EyF6T3>7ZTD#<0ZJ@gO` zHwpucaYjlBG(RN`G0{6X>JYlI#;ndpQr{Z`j^E=xEWV=49myJ0!O$XJqE)nGk*zuz zX9%KAgHKB-#gNF};YO*h(dayjbp9o=w|VD4YD5EV={~3t%)C5Ld8i76=JNW z!YPFox1lzLvX-n0CxusvxS-Jb!tKSW?Z(Jr9oqv69!2lh(C}LDIuHnn(qIyYlid zQiDtRtuf3W^YmnVtotThsHX!-8qhJ@B$~!uO0JY!pRcN?hmeLIw~#DMmHN}Hpo|JB ztem!i!|e5Ev5GA_&XK=PN3FO9!O#?>MHMMggOCDy$~C29=q38oejg9wQC*??W^y+4 z;XGv|Qb`nH^!+Q)pw>{BBao~>C7TcxTT`uC^L|^gCdjhJ9u7^goV-4?7LMJi5A;7% zhM~krh(d?8v0Xr6RcmC~k-2(3k;+{a@7`$FT6$}}56tbQfAxVW)W8|?dn+GUn za~Pl|ikuRo6sOG{%8YCj{BgX)5s zi*-OYOqdE=#26Mj7Uby|Ysra)@GwqVYVDmF;FC^7U(lw(1ez^!dg*iT4)xAms`Ho( zTo?i|#00$&2ZH8Z3&u#CQ2<59jiRvcD}xv;0nBekcME;CwcZKsoSKCa@xE;I+LM7>g1`F7MGMa zrNi0fmBHJ6d1B5+&hf+}=jR*{QsyE98F*?S#73esAQiD8h|M(^yty|@?vWSh5)M-; zQm^-6f`(k$KuJ-r*twyq;A!Tq^1pLP$GIVGFf8o8xOe2Ac&@}WNM}Xv48=e!g&9f_ zA1Bf}_sjvy(d$ql7*%NdA~@Tu2pQ^_ou(HhgwoIqo1i{_Q=SX{G;zPtfYH*SX~OLd z@?r(R6jK6{iEW4}CyDL(7^9igy-l7vwY@WUn@EzAIJF0hd^AexfYL}h(%piXtsXuq z#YEzGhIxrwd^X$KN4e6Z2Q0i`V$dEGN9nT<_PxO!ud8-tQ#z!(@_W9Fu{&~a^y$6a zC}zjQ?SOCz@oc(x%Lij*udo#Cl<~eS4UC0G_6i$!@W8RJsfPP^rBTUq^rYLjn7f=+NV@d=BfG%Mr=7Xq!y4Qe%vCf)u>pSqa!Bs z8}=08MQqy=jRSrKSH$6}QFNMa3^vY`3x#A)K1c>>xg5@>bY5jSoFqxVrBVHn(3?%k zTqOe_x|V4w{h;R9D@l5&$n+T=>VkdFTCG-~JW?{)F^wa&BiqJs&Mer;oT8Fpkp%(+ zL&xIpv%w|V@>oeRcBg#i?0_bU630`8hH^gD`2pH%M43;U$G-F}l;_oyCnTy=9fJx< z874dqWVQrRmi{j|D256&Khj8GyR14+ICVwIX>|32WfDtGUw4sOBUL_bbYrNCI+hMu5$0p`bQ zZ%A%9p*~=fM=X5nY;?lGq?CsB@mztm$^0Sc(oYtTAXXA*t zHgmY1J4#r%XEtwmqB?ApROczGkZ~-L@?4b;lmU~FV|Gi4LM)TpWHu!ZmSb~+nVCuX zOuu;58{Q{T;#Pr%ejwFbX+0xzopRKZwmLQ(_!Lox8X;>om)x~G$9zbvGL9?=)hVC! zq`^U7PGyVA4KvwbTT^W3F@g1laeh3RKcpv5ZTniFOvogU2or*`QcS!M$|o*44h0>6 zWzAeicB8lAH+Y0Ur87wM?#qDW4ID-7oMxBzB;<`K`FR+y!8;|WJ)e^2q^Y~)_rntx{;g29-zT{&kLaEWu+BM)hN!|9dQ%!w5AT% z(sqg`((5(FvHZwzpTOe-IqbV{ixjRK#NvOYfo1AQ!`*h~fi8_+;B|@%9Td&B1 zBfAYCj_wWyYQuJKu%!;DxDrOK|EZfsYzt^=?+Cm|`;MmMIXz?Inf`s>x zxdZIc#GjJex-v6GxNv0+z8--PVsanO3&O#^h{dzR5p|(GDEXKJ2$5VMNx4>0)c`S^ ziNvKTggKtUpph@C5`6VC@efsdW3uK9X}6v#o7qS(t27+yq@-Oz=50l4Td5|yI1<^) zN5e=!lNeBKg<3g@sS`p46lY<{1ckH0(dk?z#yVX7{q0;kJ z72KQVLz8zWgI$;EI`^0IK{Zwf=?WSD6Y_;){%d-nM)Lg5TEQu$nkkLWh^-KBEFT={ zLyzivvXhpop_T&rJkn%y3ot(~qMQ{g@P@NU;UbG1k_Xzz7-^4Zc})X_7~x&T_XCn2 zB(R{%_+{vF-aJ}+)Ax$(SS`?*hfp<5i~#gV-SDyQ&2UTMIMjP~y!pev4Fg~>QjF*- z9EJ#XsL55Q;}acfkmkQp6VF=*`xl*-IDgd=r)MWG&-P!7c1L-|9*P%dt(G`>Ar4;c zpS^5VvD{e;OPFn;kF3!Elsci`t)I?Y$LHd-b@sY_eh#fY|5@yxo-1c_dDS|0PO$kmZGfk9zK<2!#{#30w2xm>gXoBR)_(cwT)a9tI&7Vhx9$_@ zohow7!&b)uIDTv&+Jjoz?*P~LQ~xQ`C8fTIc^qFUmx^`dof-u@A$ z7fM1mor~8kiSN!iA?WBx9JdYt-u<(m1;!<8A0Qr_v)1W;8_YFmSznn z52&Q|BhtXd@ez&|vtq+|awq}Y*nbJshR8JL-Fef7&T)p)lV7DO@FJP~pMi`{#OwW^ z*)jWPNge>E_T09q0*E4^&i&^nh=b<`<*I z!n1g>-#)rH%g`9~d;%!MCW+ScgeW5GRH{S+qWuE8I(Q{#Pgtw=XYmTA;&}^-?H~Tw zM$W_iIItEvZHbc;*@DC)F*dqu3ge^lIS%~j`@cUy=N$jT4jOS$4(!vOlLUv>nNOHVoBDC5^qZ5mYej|lOpqyZh=Ix!}%^p?9`_8G1Btn zz8g0VXi^}{^c8M2SoL9VcalVY?AQ{4C855ylL@+OTnN=i#>$AO?!_s?Y#h7t;3-j% zv`cSj9+{#RLmQ&V9pcasVqJTz3X_)~oiyPadD24B0MwOHzK6n|gOu^{R-Rme3Li;j zEpa&}M;>g7+Au@VsxyDm_CPB1i#BJMI7>%e8ZpRMqR$Wh4!fdl>DUl+y_>^53KxW z53G#$5XmZFx`m+SjM*)D6Y$MSRFFONPMd}Sz|U6zLEje`cbrX~mWPJrky=%}P+cT( zWdvfmkU5Pnny*ztYvM$ly*03WTgRN=ndU11rTRT<^NO6eU}!mO*Iv1q+MGU{W?=t$ z=i~^qjiaAUO?j6nKu$hoffWCbZmZrrswImcz4{Y5LyX@WVLyo16f>X}PHL8C9jmf^mPEDFYDr(DqF-6gin(`xT|&Nzf7*ZL#OjY`LDUN8fMdE;np4Y@XL zo}-!1C%O8Lzq~af2TRU)c>S1)c)&lxTMr{t$t|>YKbEz}-n1h4?)KD)aLYd8vyFf~ z*zs@~FU}>#xa7*sN^&zr=^Fmf(J9jLI9ht9yMhBe?y}bur&0$p<@*&shqvM2Ht^Jn zM)}vf)g7@vPyzt05Y$E_!Z0b-^YLYy7AvBdiJMAf0wy2j@ri;KXs1}PP?y?%oygw zOmJ=;GhLU*f}8>)^(ogsG`1^tIm(8SEmz;zY*g$f_m7TF4!WJAlk+axl3JZ}*(7}I zMw8ceqfPkOB@bIUtwPC7_*5{0xDGdoK4ci&@e0@|VDMi~soR}3ws5nA$`yUOUDy$` zPS)*;a(RM+Z$NP_q3~1Ag(go9mnjTlCFsJYe5t}Qn$VX8gIc}<@>r(ua2D{n=`w{e z{OjBLySZRs4qbb`PC;4D62Urr(&W-}?%=W8;$ojY6N6DCdE4Z}2d z%hyS!P<+Bn-lYyXiNln3$q#qge)#yjiw79q-DqJUY?M~noayInG+h4Nz38YsIQ7&j zS0#@3UsF;QQQml3F-f3@ck`yVUFq4&M1ays`ucYL!EQnr@)^>HF$DP()#|r-oxaNf z{l}A|1g6H84fXNG>*uYr?#T-*cJaE^5#_B73v4s6tpRf!#_p)w8-=iu*-akfb}{>O zGMiqK15oxAsK?z~FYeAM!d(sgY1iYEcH^D<9`=n?E%RQk6^!B?bwTgthE+U!_!yyd z-=+}txFIn)C!fNaxi2SJ5+tvgccvy!U}7P_(KR-7}1`%>1fx^xb#$ge=@w?ZZQ$74^!XbGP$z z=e+e=zcR#^+xn?>fQK6LmBA_9!}gitjrhvQLgntC9lSDLZ5l#W<^xD%umOn55uo2S zt#_@T4vsE5z?ezQ)>D$3Qd+eSX+dl`xv39~xs?(8-==E5OQKsVdeZ46-lpe^$jNR| z&s3Ctg9agUMd7oN7hJ|y1_@EjX5@YtM!Zp04+r4Lw@i8kVpYpm*g5b_26c`P^?!N(K?4xSuN z-1w?YL8%m6*qJ4nu*h4GMyLDduVlVMGoJ?t5^iNurJ|Ho;`rj|sFDe(EYkwO5C^kK zd154Zz#B-5ieuZm#wZ9~lue_IUkOPn`9YFoL*^(ka&3sWe1I3dE6N+KeY**fBqCrcy&3RqYPd^Xb@IH;qm9+~BvO*LAp9}S!d@0d}PyOZA zoC!>|qCPVj+L0jBag8p$IJfSlxHRfs-l^`8&bIX6j7w=c7!n?0l*2yg_qY+DNvY(v zHJH~HsM&XD>cIMa7zU5%h74dYrV|8A1dkY{HHm(^xviWgWqCT}QKx*ETPH~MOlJcs zz|*{%so(9P2;`|Zz=6)}YaB_Bd|#{TfNqJFV23ZS-@6)sS}yEY)^84yLnFpjB4Ut7 zdDVE8eAN4>$enay?*r=+7JDjrD?R58FG@dHeH?5$%>__8w){IHy$mjPT6Sf>J#J9-0CUR(IFki zb--s7yujTjh+!Mzh7qi?NTKVR9{avGxrARnL*WY>0L!b6T28GSxXh^P;+h zjdWd^l-V3+Q3mMrV6Xt_wc#wTN(gdV$tH;|z=>+f%LgZ$NjlXI6_AY-4r)=d=~SDl zI5jG>QOm@2SPEGy<`R?q)lheN2V(G5et??{Y)ZOH=D;CVr(QH0#b)+9>plDzDHcrD zTuk(+GEzot-J@W9lURO(2E`ty^TMB$U2xCOC=5~AvAluwJh(yz+~>#&dI?K-9z$AKcy!sqa~HyQyII<=(qWvm-c#<3^GTHa%ZLO_+@U@tsb*sVNqloik-G4!i%;Iy)&poDM3x zLjSs%n!h|`bXc_0I+q|)d2AqlUyI)Zqv+$Vo%z|WdOG9Bbz_w1UPw(mZcroe4>A|% z0{)5LSIk6)$sn-SoIzmI0A0Id!^f>4lVkoi_4@BE40BRkntv+h?)wA;tnMRma@cCLh`}?Ks@Q^J0MLl zcQH{4wj!m^6wf70X&?37V90Q>q^Io4mZD3F(%Y?ftVl=-BdH4ymFOfo;?~O4#L73# z52^oiuFi+$0QB|>P&a&Os4u`V_1ksza6^6Bd{?PZV%jZ9m-Nx5D1X<{k5EXPc|Es` zyq-)| zQ`lA8a%tC{P0%EvpPHsAt@)&q15??7Se@JqGVd;@;cOzHr|HD73tAmBMd?>50N`!I zs41c& zUkTDxa$X}u;?cpQox&_|Ibhd!3rqK=o_oDp(9Ol1Za7yjDV6{#47dU+;?{Z|%nMWY zY7<`^a@47XX?oKi3BvBe3X+~1#U(!$zJcNPC%44h*Pba8Wp#1ib8$RdfMY)z_?Lbx zk&J9&85BzxDfO@$hkkh>kUA0cqNZVOF}+W2VEpB!F^_|xy3*#pL|4TG6JUCxfb7I~ zrj%<{Cen1=Eu2(YsDY;x0``GZd(%emxr`31@A@=K5xuxBQ(%juoTi|T$x@*Dm$# ziB7YS9MY;t;}c;E05(wI?EcXk5Hz3bjBtFC`IZf4M&0%lq-r)aO6D_CvnAuZN%ymQ?VU|?x0JqJ!R7F(f%t| zhZKc!bvV>Uxky{&=qFGa?Z2#ts}ra*F$T*{3=?x5l0Aed_-}4AF1_y~=(1q=BFULyyXdT_b{B3>KjsIw}UzG(Zi)0)qcz z=@r7kO0tojs9lSsKy#~C8uI>5wrdnm=!lBpX>|&FNfa9sb5w8%)XCb*qfMiOEfv@i zS!U$`d9Ng!R&*M=To?bS13AC zdgwvkI5pYxK>AlxbiH^a9#y2P2hoQ8MvbkJ431Dwdwgq*Ru_`#%4G}84Y4LBb|I_G$`hi*8kyX5DOjz%V#<}oS6|(FW;ZQyEl5wfPcWiPb2!%qxJh2c2%abJ#wEa%<0`nAE6B;wY8H zAmbQNe0*{a^>&>lgg;t&%}&uy3ak+}LS?d%)NRi!w0WkBNbqLpyOi$n*I!{_8SsmT z0!DTA=BEp)s=hBbER0#R;jvaIS2XHGyG>a|HKf#WQ<-kyHRX9 z!a>i&l>YG&6u(oc_}OnR*p`(4ayB*{C8*(%d#N>~t1ya5CwjgA)2oxtIl70VBRa5t z(=(3|VA!xz?&hmJe4=Henj9c|QR3xt!y3ps+cS@nGAUMw;${aGu2-|NWoz6vOTfj3h-0)AsFfQ_oOL#J})QUw^`jm_hIg(Sd zTvEYfGhIbZMU{>OFqVWlBai9m4#ud88RhMgl@wl(gn|F&TK&{|rZOOxnw4AziEEmW z-grlQ6xgJ!Jz89}!9}l@DB3j6LIBP}Hcd{DbM|N1-AFNm&-D^5mOAVky14H}8z(2n zS4$Cf!??#`EGhN6Y0^AC!9%a+uKB1h*65LA+ki<=((RFKHjeuiE|f%NMjs1Ha(xpm zG`?6p!$M#MotSoI$#rFpMoUK;#L|nM1K?Wn`0K!4Qj85x+iV{UVK`w3+Y3WiG7e?u z%nNRmkh{nZ^teiNsG5ShRMK#gcZlY61W2$(bDF zki27i{Hr-K{-{*u0-tKKayO7QP#RO85h|n2PXH^=W6C_|7RphAu9#t5!`2xe_pSr) zAQ<(+n>*>mE~N8018K6o9Oz8r3WaPT1IrxK5r+byI8G`xOi8TbGDjM6*W65mDIfxt8tkQbN%RjZ6+FjejK`CETMghSG?sOgR$^B#O}y3`VvHihEfoY&IKAysENUuf@5lAl;F1En%Dh;3^8>E~P|8b+<~w6X zO}4|x+;wJ#YmPRf6bA3hD|k_QCHL6GL_l(0n5ws%S5025v1%4eEvuN+qUxvvsjiMr zUZMuKGIytw3vITA-v}=kN#WIcd8uAr+An8gcsv`s(RI0QJ;o=qak?4v+@UPDdcX4D zm-6pP1$Ko0i`y8hram>`qjL+@hTnsE)Gu}NhvrVIQ1CxY?W&3ujY7R}{XUkbdWF+r z5=P-{m@6>7|3{yR&hzmPw6m({;TJ2^tpQ21(vwE_zS}>S7+5hnNRpE9a|nJ462Lg^lM&3?5opW48K>elIG{2$`??8*W zI6ZBh9qe~nwS3#WlZCI89YwNZ#Jj3vK;UFJM&k?g3E%3m_dwF=NZ$)<_Fn|ZCrYptV-(vnYB@Wq( z*BTAl!)V@OHkzqH0SNBnl}gTS*rkD|{nv_+4K4|>ZAlsoBvc3{NK%}b3Nx>}!^2Tm z=*Bcuc z{{#Ns$N%^m9}a?WH5(2`o_!Betd1~-DhDe_y&+Fjgw%=`My-x0=&-x;1|UP2C6Uy#L&P?mzdR&-nTO0pX>hJpdpB04~A&nE(I) literal 0 HcmV?d00001 diff --git a/Changes b/Changes new file mode 100644 index 0000000..c9af799 --- /dev/null +++ b/Changes @@ -0,0 +1,6 @@ +ncpfs-0.1 -> ncpfs-0.2 + +- should be compileable with gcc other than 2.7.0 +- first attempt at read/write access +- more complete ncpmount.c +- included file ipx.tar \ No newline at end of file diff --git a/Makefile b/Makefile index a37b865..f41c49e 100644 --- a/Makefile +++ b/Makefile @@ -6,8 +6,8 @@ INCLUDES = -I/usr/src/linux/include CFLAGS = -Wall -Wstrict-prototypes -O2 -DMODULE -fomit-frame-pointer \ $(INCLUDES) \ + -DDEBUG_NCP_MALLOC # -DDEBUG_NCP=1 -DDEBUG_NCP_MALLOC -# -DDEBUG_NCP_MALLOC CC = gcc -D__KERNEL__ -I. AS = as @@ -22,26 +22,29 @@ ARCH = i386 OBJS= inode.o dir.o file.o sock.o ioctl.o ncplib.o nwcrypt.o -all: ncpfs.o ncpmount +all: ncpfs.o ncpmount ncptest ncpfs.o: $(OBJS) $(LD) -r -o ncpfs.o $(OBJS) -ncpmount: ncpmount.o +ncpmount: ncpmount.o gcc -o ncpmount ncpmount.o ncpmount.o: ncpmount.c gcc -c ncpmount.c -Wall -I. -g +ncptest: ncptest.o ncplib_user.o nwcrypt.o + gcc -o ncptest ncptest.o ncplib_user.o nwcrypt.o + +ncptest.o: ncptest.c + gcc -c ncptest.c -Wall -I. -g + ncplib_user.o: ncplib.o gcc -c ncplib.c -Wall -I. -g -o ncplib_user.o nwcrypt.o: nwcrypt.c gcc -c -O2 -Wall nwcrypt.c -ncpumount: ncpumount.o - gcc -o ncpumount ncpumount.o - dep: $(CPP) -M $(INCLUDES) *.c > .depend @@ -49,7 +52,7 @@ clean: rm -f *.o *~ realclean: clean - rm -fr ncpmount ncpumount .depend $(DISTFILE) mnt + rm -fr ncpmount ncptest .depend $(DISTFILE) mnt modules: ncpfs.o diff --git a/README b/README index e584f28..ffdb0cb 100644 --- a/README +++ b/README @@ -1,90 +1,47 @@ -This is version 0.1 of ncpfs, a free NetWare client for Linux. For me -it works with 1.3.32 and 1.3.35. +This is version 0.2 of ncpfs, a free NetWare client for Linux. For me +it works with 1.3.32 -I know that this piece of software is VERY incomplete, as it only -gives you read-only access. I have to apologize for that. But I -thought I should make it publically available, because I have tried to -ask several people about the legal status of the code. I did not get -very satisfying answers. So I publish ncpfs to open it for -criticism. If nobody complains, I will go on working. +I know that this piece of software is VERY incomplete, I have to +apologize for that. But I thought I should make it publically +available, because I have tried to ask several people about the legal +status of the code. I did not get very satisfying answers. So I publish +ncpfs to open it for criticism. If nobody complains, I will go on +working. -To install ncpfs, just type 'make', 'insmod ncpfs.o' and -'ncpmount server mount-point user password'. Please note that your IPX -system has to be configured correctly. There has to be a route to the -internal network of your server. I use tools from the dosemu-0.60.3 -distribution to do this. Once again I have to apologize for this -cryptic description, but before I'm sure that I'm allowed to do all -this I will not do more. +To install ncpfs, just type 'make', 'insmod ncpfs.o' and then +'ncpmount server mount-point'. Please note that your IPX system has to +be configured correctly. There has to be a route to the internal +network of your server. Please see the file start_ipx for an example. +I use tools written by Greg Page, Caldera. I hope I did not do too +much harm to their business. For your convenience I included the file +ipx.tar made available by Caldera. -I read that Novell is not very open when it comes to technical details -of the Netware Core Protocol. This might be especially true for the -encryption stuff. I took the necessary code from Dr. Dobb's Journal -11/93, Undocumented Corner. I asked Jon Erickson about -the legal status of this piece of code: - - ---- -Date: Thu, 12 Oct 1995 13:44:18 +0100 -From: Volker Lendecke -To: jon@ddj.com -Subject: legal status of your source code? - - -Hello! - -I hope that you're the right one to write to, you are the first on your WWW -server. If you are not, could you please forward this message to the right -person? Thanks. - -I'm currently exploring the possibility to write a free (in the GNU GPL -sense) NCP filesystem, which would allow me to access a novell server -transparently. For that I would like to use the encryption functions you -published in DDJ 11/93, Undocumented Corner. I would make some cosmetic -changes, such as other indentations, minor code changes and so on. But I do -not know if that allows me to publish this code under GPL. One alternative -would be to publish a diff against your listing, but that would probably -contain much of your code as well, and it would be very inconvenient for -the average user. - -I think that you have some kind of standard procedure for such a -case. Please tell me what I should do. - -Many thanks in advance, - - Volker - - +=================================================================+ - ! Volker Lendecke Internet: lendecke@namu01.gwdg.de ! - ! D-37081 Goettingen, Germany ! - +=================================================================+ - --- - - -I got the following answer: - ---- -From: Jon Erickson -X-Mailer: SCO System V Mail (version 3.2) -To: lendecke@namu01.gwdg.de -Subject: Re: legal status of your source code? -Date: Thu, 12 Oct 95 5:42:56 PDT - -Volker, -Code from Dr. Dobb's Journal related articles is provided for -anyone to use. Clearly, the author of the article should be -given credit. -Jon Erickson - ---- - -With this answer in mind, I took the code and made it a bit more -C-like. The original seemed to be translated by a mechanical pascal->c -translator. Jon's answer encouraged me to publish nwcrypt.c under the -GPL. If anybody who knows more about copyright and sees any problems -with this, please tell me. +For the curious: the file ncplib.c is usable from user space as well! +Look at the file ncptest.c for a possible use. I use ncptest to check +my assumptions about the widely undocumented NetWare Core +Protocol. Maybe this is the beginning of a free NetWare API for Linux! +I would be happy to receive your comments on this. +LIMITATIONS (compare these with smbfs :-)) +The limitations ncpfs has are the natural limitations of the NCP +protocol, which was designed with MS-DOS based PCs in mind. The first +limitation is the lack of uid, gid and permission information per +file. You have to assign those values once for a complete mounted +directory. +The second limitation is just as annoying as the first: You cannot +re-export a ncp-mounted directory by nfs. It is not possible because +the NFS protocol defines access to files through unique file handles, +which can be mapped to the device and inode numbers in unix NFS +servers. NCP does not have unique numbers per file, you only have the +path name. I implemented a caching scheme for inode numbers, which +gives unique inode numbers for every open file in the system. This is +just sufficient for local use of the files, because you can tell when +an inode number can be discarded. With NFS the situation is +different. You can never know when the client will access the file-id +you offered, so you would have to cache the inode numbers +indefinitely long. I think this should not be done in kernel mode, as +it would require an unlimited amount of RAM. diff --git a/dir.c b/dir.c index 2a1c611..6b9ee20 100644 --- a/dir.c +++ b/dir.c @@ -1,4 +1,4 @@ - /* +/* * dir.c * * Copyright (C) 1995 by Volker Lendecke @@ -60,6 +60,23 @@ static int ncp_lookup(struct inode *dir, const char *__name, int len, struct inode **result); +static int +ncp_create(struct inode *dir, const char *name, int len, int mode, + struct inode **result); + +static int +ncp_mkdir(struct inode *dir, const char *name, int len, int mode); + +static int +ncp_rmdir(struct inode *dir, const char *name, int len); + +static int +ncp_unlink(struct inode *dir, const char *name, int len); + +static int +ncp_rename(struct inode *old_dir, const char *old_name, int old_len, + struct inode *new_dir, const char *new_name, int new_len); + static int date_dos2unix(unsigned short time,unsigned short date); @@ -103,15 +120,15 @@ static struct file_operations ncp_dir_operations = { struct inode_operations ncp_dir_inode_operations = { &ncp_dir_operations, /* default directory file ops */ - NULL, /* create */ + ncp_create, /* create */ ncp_lookup, /* lookup */ NULL, /* link */ - NULL, /* unlink */ + ncp_unlink, /* unlink */ NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ + ncp_mkdir, /* mkdir */ + ncp_rmdir, /* rmdir */ NULL, /* mknod */ - NULL, /* rename */ + ncp_rename, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* bmap */ @@ -364,7 +381,6 @@ ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos, date_dos2unix(0, finfo.creation_date); entry->atime = date_dos2unix(0, finfo.access_date); -; entry->size = (attr & aDIR) != 0 ? 1024 : finfo.file_length; entry->f_pos = total_count; @@ -437,7 +453,7 @@ get_pname_static(struct inode *dir, const char *name, int len, } #endif - DPRINTK("get_pname_static: parentname = %s, len = %d\n", + DDPRINTK("get_pname_static: parentname = %s, len = %d\n", parentname, parentlen); if (len > NCP_MAXNAMELEN) { @@ -458,16 +474,16 @@ get_pname_static(struct inode *dir, const char *name, int len, char *pos = strrchr(parentname, '\\'); if ( (pos == NULL) - && (parentlen == 0)) { + && ( (parentname[parentlen-1] == ':') + || (parentlen == 0))) { /* We're at the top */ - path[0] = '\\'; - path[1] = '\0'; - *res_len = 2; + path[0] = '\0'; + *res_len = 1; return 0; } - + if (pos == NULL) { printk("ncp_make_name: Bad parent NCP-name: %s", @@ -501,7 +517,7 @@ get_pname_static(struct inode *dir, const char *name, int len, *res_len = len; - DPRINTK("get_pname: path = %s, *pathlen = %d\n", + DDPRINTK("get_pname: path = %s, *pathlen = %d\n", path, *res_len); return 0; } @@ -845,10 +861,191 @@ ncp_lookup(struct inode *dir, const char *__name, int len, return 0; } +static int +ncp_create(struct inode *dir, const char *name, int len, int mode, + struct inode **result) +{ + int error; + char *path = NULL; + struct ncp_dirent entry; + struct ncp_file_info finfo; + struct ncp_dirent *ino_finfo; + *result = NULL; + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("ncp_create: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } -/* The following are taken directly from msdos-fs */ + /* Now we will have to build up an NCP filename. */ + if ((error = get_pname(dir, name, len, &path, &len)) < 0) { + iput(dir); + return error; + } + + if (ncp_create_newfile(NCP_SERVER(dir), 0, path, 0, &finfo) != 0) { + put_pname(path); + iput(dir); + return -EACCES; + } + + entry.attr = finfo.file_attributes; + entry.mtime = date_dos2unix(finfo.update_time, + finfo.update_date); + entry.ctime = date_dos2unix(0, finfo.creation_date); + entry.atime = date_dos2unix(0, finfo.access_date); + entry.size = 0; + + ncp_invalid_dir_cache(dir->i_ino); + + if (!(*result = ncp_iget(dir, path, &entry)) < 0) { + ncp_close_file(NCP_SERVER(dir), finfo.file_id); + put_pname(path); + iput(dir); + return error; + } + + ino_finfo = &(NCP_INOP(*result)->finfo); + ino_finfo->opened = 1; + ino_finfo->access = O_RDWR; + memcpy(&(ino_finfo->file_id), finfo.file_id, NCP_FILE_ID_LEN); + + iput(dir); + return 0; +} + +static int +ncp_mkdir(struct inode *dir, const char *name, int len, int mode) +{ + int error; + char path[NCP_MAXPATHLEN]; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("ncp_mkdir: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + + /* Now we will have to build up an NCP filename. */ + if ((error = get_pname_static(dir, name, len, path, &len)) < 0) { + iput(dir); + return error; + } + + if ((error = ncp_create_directory(NCP_SERVER(dir), 0, path, + 0xff)) == 0) { + ncp_invalid_dir_cache(dir->i_ino); + } + + iput(dir); + return error; +} + +static int +ncp_rmdir(struct inode *dir, const char *name, int len) +{ + int error; + char path[NCP_MAXPATHLEN]; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("ncp_rmdir: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if ((error = get_pname_static(dir, name, len, path, &len)) < 0) { + iput(dir); + return error; + } + if (ncp_find_inode(NCP_SERVER(dir), path) != NULL) { + error = -EBUSY; + } else { + if ((error = ncp_delete_directory(NCP_SERVER(dir), + 0, path)) == 0) { + ncp_invalid_dir_cache(dir->i_ino); + } + } + iput(dir); + return error; +} + +static int +ncp_unlink(struct inode *dir, const char *name, int len) +{ + int error; + char path[NCP_MAXPATHLEN]; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("ncp_unlink: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if ((error = get_pname_static(dir, name, len, path, &len)) < 0) { + iput(dir); + return error; + } + if (ncp_find_inode(NCP_SERVER(dir), path) != NULL) { + error = -EBUSY; + } else { + if ((error = ncp_erase_file(NCP_SERVER(dir), 0, path, + 0)) == 0) + ncp_invalid_dir_cache(dir->i_ino); + } + + iput(dir); + return error; +} + +static int +ncp_rename(struct inode *old_dir, const char *old_name, int old_len, + struct inode *new_dir, const char *new_name, int new_len) +{ + int res; + char old_path[NCP_MAXPATHLEN], new_path[NCP_MAXPATHLEN]; + + if (!old_dir || !S_ISDIR(old_dir->i_mode)) { + printk("ncp_rename: old inode is NULL or not a directory\n"); + res = -ENOENT; + goto finished; + } + + if (!new_dir || !S_ISDIR(new_dir->i_mode)) { + printk("ncp_rename: new inode is NULL or not a directory\n"); + res = -ENOENT; + goto finished; + } + + res = get_pname_static(old_dir, old_name, old_len, old_path, &old_len); + if (res < 0) { + goto finished; + } + + res = get_pname_static(new_dir, new_name, new_len, new_path, &new_len); + if (res < 0) { + goto finished; + } + + if ( (ncp_find_inode(NCP_SERVER(old_dir), old_path) != NULL) + || (ncp_find_inode(NCP_SERVER(new_dir), new_path) != NULL)) { + res = -EBUSY; + goto finished; + } + + res = ncp_rename_file(NCP_SERVER(old_dir), 0, old_path, 0,0, new_path); + + if (res == 0) { + ncp_invalid_dir_cache(old_dir->i_ino); + ncp_invalid_dir_cache(new_dir->i_ino); + } + + finished: + iput(old_dir); + iput(new_dir); + return res; +} + +/* The following routines are taken directly from msdos-fs */ /* Linear day numbers of the respective 1sts in non-leap years. */ diff --git a/file.c b/file.c index 581be2b..e582a2d 100644 --- a/file.c +++ b/file.c @@ -93,9 +93,6 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count) return -EINVAL; } - if ((errno = ncp_make_open(inode, O_RDONLY)) != 0) - return errno; - pos = file->f_pos; if (pos + count > inode->i_size) @@ -104,6 +101,9 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count) if (count <= 0) return 0; + if ((errno = ncp_make_open(inode, O_RDONLY)) != 0) + return errno; + bufsize = NCP_SERVER(inode)->buffer_size; already_read = 0; @@ -145,10 +145,85 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count) return already_read; } +static int +ncp_file_write(struct inode *inode, struct file *file, const char *buf, + int count) +{ + int bufsize, to_write, already_written; + off_t pos; + int errno; + + if (!inode) { + DPRINTK("ncp_file_write: inode = NULL\n"); + return -EINVAL; + } + + if (!S_ISREG(inode->i_mode)) { + DPRINTK("ncp_file_write: write to non-file, mode %07o\n", + inode->i_mode); + return -EINVAL; + } + + DPRINTK("ncp_file_write: enter %s\n", NCP_FINFO(inode)->path); + + if (count <= 0) + return 0; + + if ((errno = ncp_make_open(inode, O_RDWR)) != 0) + return errno; + + pos = file->f_pos; + + if (file->f_flags & O_APPEND) + pos = inode->i_size; + + bufsize = NCP_SERVER(inode)->buffer_size; + + already_written = 0; + + while (already_written < count) { + + int written_this_time; + + if ((pos % bufsize) != 0) { + to_write = bufsize - (pos % bufsize); + } else { + to_write = bufsize; + } + + to_write = min(to_write, count - already_written); + if (ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_id, + pos, to_write, buf, &written_this_time) != 0) { + return -EIO; + } + + pos += written_this_time; + buf += written_this_time; + already_written += written_this_time; + + if (written_this_time < to_write) { + break; + } + } + + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + + file->f_pos = pos; + + if (pos > inode->i_size) { + inode->i_size = pos; + } + + DPRINTK("ncp_file_write: exit %s\n", NCP_FINFO(inode)->path); + + return already_written; +} + static struct file_operations ncp_file_operations = { NULL, /* lseek - default */ ncp_file_read, /* read */ - NULL, /* write */ + ncp_file_write, /* write */ NULL, /* readdir - bad */ NULL, /* select - default */ ncp_ioctl, /* ioctl */ diff --git a/inode.c b/inode.c index 0eeccf7..742158d 100644 --- a/inode.c +++ b/inode.c @@ -34,10 +34,11 @@ extern int close_fp(struct file *filp); static void ncp_put_inode(struct inode *); static void ncp_read_inode(struct inode *); static void ncp_put_super(struct super_block *); +static int ncp_notify_change(struct inode *inode, struct iattr *attr); static struct super_operations ncp_sops = { ncp_read_inode, /* read inode */ - NULL, /* notify change */ + ncp_notify_change, /* notify change */ NULL, /* write inode */ ncp_put_inode, /* put inode */ ncp_put_super, /* put superblock */ @@ -328,6 +329,58 @@ ncp_put_super(struct super_block *sb) MOD_DEC_USE_COUNT; } + +/* DO MORE */ +static int +ncp_notify_change(struct inode *inode, struct iattr *attr) +{ + int error = 0; + + if ((error = inode_change_ok(inode, attr)) < 0) + return error; + + if (((attr->ia_valid & ATTR_UID) && + (attr->ia_uid != NCP_SERVER(inode)->m.uid))) + return -EPERM; + + if (((attr->ia_valid & ATTR_GID) && + (attr->ia_uid != NCP_SERVER(inode)->m.gid))) + return -EPERM; + + if (((attr->ia_valid & ATTR_MODE) && + (attr->ia_mode & + ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)))) + return -EPERM; + + if ((attr->ia_valid & ATTR_SIZE) != 0) { + + struct ncp_file_info finfo; + struct ncp_dirent *dirent = NCP_FINFO(inode); + + DPRINTK("ncpfs: trying to change size of %s to %ld\n", + dirent->path, attr->ia_size); + + if (attr->ia_size != 0) { + return -EPERM; + } + + if (NCP_FINFO(inode)->opened != 0) { + ncp_close_file(NCP_SERVER(inode), dirent->file_id); + dirent->opened = 0; + } + + if (ncp_create_file(NCP_SERVER(inode), 0, + dirent->path, 0, &finfo) == 0) { + ncp_close_file(NCP_SERVER(inode), finfo.file_id); + dirent->opened = 0; + } + error = 0; + } + + ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir)); + + return error; +} #ifdef DEBUG_NCP_MALLOC int ncp_malloced; diff --git a/ipx.tar b/ipx.tar new file mode 100644 index 0000000000000000000000000000000000000000..f4b1ecc452032c6207247fc2a63298bc2bd48c34 GIT binary patch literal 40960 zcmeHQYggOImhG?Buc+bPbZi2~Hm?kM%+SOnUPBueklWoW$?`I`4C)xkBiTuqbpHG7 zeX2?iTQZO)tDOcP88MkZ@&Kj z@ciCz(s$M4Xx#UL>e*8#Nt*Z`QnP8j@x{o^CY`$DU^LFAMdQ%(Por$&(DNrBRzPXl zQq^)NETd^~w44$Z>jS-LSMc3WHO>d+s9PUEuYdNz^@c%luezFopp-?~ey% ztb`keOUfxNykw3obuUuO%jxkwc@_A71%ttx*Zyl~CR047!fYHzrs!)Q!?OLG|EcoG z`Q$ig!#VGcI(qp#nEI0-7?wFuwTQ*RtjnOhfhuD}VXqsxz4K97KUz`?`|X8_dh$fo zD(bJloKmTjo9p=SWiyozb5fA;sCk^qSD5XO=8?@-A>EWhcRUGwRe$7^J}Gw?xvIFw zySujRye{u&%p1C(bv>Qvxn`D~Vc?&Z^(t^|=nV=Q?!`S`D*c?E*GfhG#}kG2^+?`(QhL~0dT1=}Wcj!W43xB|}A?))C^`vevGb8__>2jO| zj7dgV!xwOaBGvMHNYCj1@u+W8|F5sD*EdA}udi)vtT#5b{=adj|KA4vB+7n{{-2}k zLnQiFuo6(&&^wt@^Ycss-yM7Sx8nKP%mt=`NgiY~|4jp;JNA0Y*b&|U7DCDEKZ0Q) z>7S*er!@3#zpq{`kKU-h`_AjRY7j!z@6g;)uQ2eAKRG{f!zqou?+$14XEbx@Zf@^w zUZ#`+lBcnge02D2dt#WBCVu3d`fguT#uCy+{rgl(N+mYe!oyml z+E`dBL4b62p_4T`NNI>AB+pi-pJ^*;;i$cRka@%eU934ibHi3E^R#*VqIuYAX;bPS zeRlvtQtjR2KMtBlFdMx8bAv%S)xpY&Nt+pQrQ(R?G7N&ZlTjxrV+h8pzmILh74`Galt*c^C8;lZ_2-+anbjpt3YE$u=Ku4-18Qlkn&R?Ls(WTE zOgHw3ZhFcf6g_sAWTk|x&H-tt6I!lTf##a0JDlq8BgK|Qt4zsc>~hhM??qO+VyJP4 zsD?tADonuw#i`Q5G=G?E8}f3d@+xdgJ~Jar87V}fuxk<-JjY@&OG$G8MZylsmKG!Y z#>#LB2o0nks>RCBUcZW6&L%>%Pg7;a=84IjYI+IV6uT68XH6lN_OOy;Pe{RJ>2Vp^ zi{+>M-HAqS&lBC6TjJ=TxzpO->$LaVO;no7hlbt<;agU$`rQd1#~N8 zS!9ih(E==or?CZO?1o;-WVk=N4=bpsuh7qb-9G%|k;-a}nn=rKj#{gB%VNCveKhx2 zHE6smJbkKGk?;`&oM@jkpM)4$m^O~zf22H=qKb%54-7d*rnBC%&XnqNZL74hs1D99 zBCm&OeWp3rGC!qzy^$4Jj{W5n1C2wd##@O#VDmp`k-R%*#|G7=bVak)a>RzR5S8k6OFi&z>E^E(1tNQpT>q zpHC&r4@iFNB8xKC8e|he4L=|^Z*D)|ZnYtQupvnTwkeQ6MaA|_sf1ZITTzM%Q3yFU zo4>b?j%i%ZaCbs0)|#_R*d4;Q>R%{rm$`jP0I|Z-Vk$PwbqgG2tNrq*S=dV3>;^+~ zWg)tXvWf z^1Y~%(|F#VCx6OmyS@Lc`LE*92P&EX3Np%N+*~aBWr9;2Ft3H?@w5Hk+J$Y9tGdw` z%3rD#THpQPy)T2iPHV09zqa=Z+p<%bYU$c72wCT~K-OZoRx}w5yq*XAU!A+>L3p76 zKWN)uC06iU0)@ia1**k{a*@S6G%yEPw1O23ETfjA7Y=m?m;zr@6UtY4Ag8cPG}{nl z2iodto}i!IU*L0ExhWFPbrH^UMQuZ}ObOa#_O2sjzXg$z?r%mIJliwEAT^D%qQvs; zEV?=^B8oYDF@OKD`QCg^)Ha+ILOJ0GJaW4i&F4tQt`ieKdSx}b8SZ{d>_cFJI|dSi zE?OD>ff>kE`NQ)m6>^3@e1u>#NCS?Xxec~qF}qQu#Cp4jQyeHag2GeJ-?~?8{GRtO zR)53{slyB@(tbo&(Q1B*;aRXeq*~tIKi>Y=cB@#I`vExUdH2%uawtLtC)M0hq8tez!tIoRASqoB zrmI$@V6OYLH|P%$@0A6>RKVb%Txq8WRuiKqbq$LnZsTrDq&d?opSd3@a0=|Z@+o_K2d*c`sKvgrhc$^U3*kT{fIc}i z#pzK8kVyl%eNQ{niH(jg9$jq4!7zC5hGjkkKc^7lXFPlQMBT65*Px(Id5o0*yl)VC z!^iZKWoFHagH$cunOX)@wUp~M^+1^-s0<}i(&ZyWQNlJM0L>^f;>qx#Z~X9w%R6*^ zOqHy{BEQ=&PX9O}Id)F;uUmyn-x&(FND!2-$41gz=JA?64^UcNh zg$isL0x1!m z(h8uHIexZzUez1RW@v9J^j_}ce9Vp&iy`v>$|O_Kl)Qx5oRG;(nNg1vDVRsr_g{l; zD1LeHL^X8&2RP7^0t)K486VYW|@CFuOZv@tyd_&uwF1goNYL?|(MdHtKiy&sWEP^6r0rT}#*Fnj^%;b1OTAc$N!HM#atPXcl;V23o zKkX(AAL0rE5GQ$X6__fkJ+4(?jmNs9jK7_AO69y_(fB&PYOV42pnnHkzWw}y97(S0{{tV)6kd)0LF`sRs62tzjVhx7yO&9 zBM0^)6!=-tA6AA)b?7h1|ufJq?^YLF*hXY`Y|2As$|Eq7V-o^h&Ch!Y>NiVo7oOCQ{rsb=yEPj zK&fs(^>{Z3gL8HTnc`OQ8Gc6!VG)ZvNG0`WgGXH2IopuwAkVbT4VHynw68Cu7hY7s zgSGg&dU6dVvsxA2I7ya*kQJ|?h(nag$Rs%8&E_MnH&qnZPiFJ+{>fCnb;+kmB6&ng z5nIs?^7Z&Rl*`w!NMA1qZq6ANf{zqnHi>kTI|JDlR1rpd=YY~1i7}DV{5r$F6Fn*kRushn%Y+1 z&BvJkhu-K*@P1CjCH%j!fy)Bf`0w>b^?tqn<@6^kJ|(KYmW`rJfF$Gpnrl8K zeY5sNzSN=N0ui8N{iQuf67$N6xm>%-27}QCrEN)B2$G6i{QjGLRpVss=3OG zT}=2=-iq>)vVJ3Nh9Yh#CHK+(UWYG;Xu^%;XutEU`OC}a`i%oiYK?;CQd}{qFV`ka z>o_sudmyi-K<$bClR|uLcvp=XPC>qF>y1LiDK*O5wefQ`C%Ep*&CJ+Jw_416jme5} zZUwju!wuKs(Vw9(*(LcrmFZ~vU`y>E@QnQ42mCLRpDKmGy7EB>q>B}Xz4&Ue(G&FG zMPnf)nKHa()u5kj2}kZY7@6?>K2thPl-6nNe!*m1Rj084}oTb|Yvm!q>y8qA-{3GH?^r-t*bCTW}FZn#8~j2B!MIl2K& zGS>g#-}da+<`+>pF2R4+Hfr+zhuV6hwvGb;p8wWY*YEVdFR~a@l^&mg^9}fpBC;uj zyNXm-y>k%|Rn!mOObmlQtXqaCMvPR%;pgpm<(-d)F5jPqn=^s$;Nc!$?p9T5*Tu^V z@D>F`qYvof^u8P7wE@97Ge-zNY%Y+(7b%*Yp6bA|5CR_Si7E~Xordn|e#F1-V$<8@uNm3!no;+GS4eRHzuzj}y9bRh?~LPfJ`! zF9;zRMuFdF3<}lN&)eB+61vKCR*t``MmDs$iGz#5q@oIAlDAdVpYWi>01i#RH!K@iFdxG!Q|M*i_0+MOi!I|?0jcpM+XDEh_tw~(n(%3w{x42 z2^u#c{@-Fg6e^NEk{v}qa3hD_e`noyZq6dZ8&D!6O5|t^qa_1J^y)qd2>03Fd3_hX z7H6(ywBwF&O2H7u)S+x(M!cp}-ZNtIhY@Phq|L4y71Yrq))dU}`T-t3QfG)9guTBc zGpho;P6I1GLe*>p5rpuqJB)-0%r2emQf?WLOqQW=6D6CMGcy@`L+n^L+HxF7pd=n$ zwFl~xMuStt>|~2}0!(yfvyoy7!SGUbnESI=u4ZOU^~A)L%3M#^rh9_9(0f|v(Vd9z zZBLg;4TMq9SKfzUD+=D?cYCL)cEGcao8V5u zgU-0uSHPw5$G;CEz#FvAd5^I>q@Sm}#|o;)^nB^H#bWlos25Fg;L!U6t0>+n%6|Aqvl?7=lE(p)Vq^C1c}M(IaAwSb}Twc z8pH_V)n;7!h@98&qogm7Aq>Fb@p>BE$LlK$f%Imo#6tes^(UZwn}yPwUJGviQTNe!ioiyeE<+0_0PiaUTG z)q8I^1cSvV@DuP-uy=#zY5@Y_46%lH2!X$#4C+$h#P`W{DV#BC2MxQ3r_(!wClJlri@Nq$mg*ztOQM^4__i zwDSPMHvkziD<6%+E`zJvKH*#j{lSEhY7PIXqNA({zl&<(qbt?K=?4i=Cm5em?I81E z{2aA{x$mu@Nj!iQ3Ed%IQh}kNC)F(9Nwgo1Vh9?WVd9Z4BD=jfyFAuei!)jMf!YdQ zPLO!xOetr#@D+5V{eOP#zJ(q&yyPv|pVgyF^nbOc&wnNUBLY8)|7Y#){m-8@*Viqy zv%9zb{0M;F@_s`t{|4FNygY90F$JWNyb*kg`}3JFWg~FqvCzJQDz?-=%Ti0l=?&ek z4^bALtK~tQtQM<*@Cxp7!^-f79LIr%4mOvmL~bH_+|st*N9wh_A_czzLrQ+U3mI4@ z_|HH8>8X_ndZA>BA0xT?P_0a&aOJ$~^WQ^Li|>BT9eCXpyV?Ah_1OO}rG`Dc$yP4e z|BX%i{&##>)$f0=Z`|$wn_Pmzx~j)7C=NS`mibUgu=kf%MaS#icC;;yxOjfAx}cou z(F;XvZ%T%~UZy3o1l?i??EV=E>StZ)@RWtJq>C*RS&7&P0w;#9m+q12s`#5*d(|`}j zJVc@d#j}8WSz^PbG&pUH#b$QZsUFN?3(#JvrhJ#c1eePi&~15xSq7Zo<19eIlpK%( z^P&|$Oh#gUQ^$;_mnuGNTIh0beY~p3ng(1iW3V_}8iOXp#W3ebM>rGU+JZKZL0&Bq zwzf>o0;TM^V#BmGkac2%%Oi(DB&IO77=>ABYF9lNLnkl* zjL8o5n|e6k%t>t@W`P*#1Q~4l64D%0k25T)zBQxZ6SnC=9fqQeHzbM?$%<(f@OGg1 zk4WdUI=B-n@Mc~>3?SHV|w+J%El`!Y#0aWTyJFa-UvZQ5U(CqQg&_}SVhyu zZrqmaTR|4g`WePVJAqc9HojrgBD^V^)Bwc=N#TXsZS6Hd2(84RSc&zYK^OK|Y-mWj zR)bg&2aQL1fP;xI5GvjeHooAMaN6jE!F72p#2U&l+I#s8xQ`MidO9il&fYt&;=!qU6`zhwj$YuAf5P7Z+V5$-|z-)38Q(fW{ zo6j@i+!mwom&%KTw9QC4ope+S)x4f&;r-MQ1QGqtu;0ibRAME_-vxb%wiAA#V8Z)3 z$$MHUf~+@I*YEEC7BAWjKC%4&aQ`Ka7Ou7^#95tJua{ph(@uY*Kk_^~L8PC&3jDutpMCurpP4e#2A|G=b!r zh=&*ML>V|YuEo*sdeZh)Zvww4xRcnY8hOD94kC|>F%eg;mjTv_shP%>cI7$&KqY=$ za4W(numIAif$VZ+@dBx{{rTZ0qj;>H1s_c~|ak2JU9y KZU%nL8TfzWQ*EID literal 0 HcmV?d00001 diff --git a/ncp.h b/ncp.h index e07afbe..862d6af 100644 --- a/ncp.h +++ b/ncp.h @@ -18,28 +18,28 @@ #define NCP_DEALLOC_SLOT_REQUEST (0x5555) struct ncp_request_header { - __u16 type; - __u8 sequence; - __u8 conn_low; - __u8 task; - __u8 conn_high; - __u8 function; - __u8 data[0]; /* Depends upon request type */ -} __attribute__ ((packed)); + __u16 type __attribute__ ((packed)); + __u8 sequence __attribute__ ((packed)); + __u8 conn_low __attribute__ ((packed)); + __u8 task __attribute__ ((packed)); + __u8 conn_high __attribute__ ((packed)); + __u8 function __attribute__ ((packed)); + __u8 data[0] __attribute__ ((packed)); +}; #define NCP_REPLY (0x3333) #define NCP_POSITIVE_ACK (0x9999) struct ncp_reply_header { - __u16 type; - __u8 sequence; - __u8 conn_low; - __u8 task; - __u8 conn_high; - __u8 completion_code; - __u8 connection_state; - __u8 data[0]; /* Depends upon request type */ -} __attribute__ ((packed)); + __u16 type __attribute__ ((packed)); + __u8 sequence __attribute__ ((packed)); + __u8 conn_low __attribute__ ((packed)); + __u8 task __attribute__ ((packed)); + __u8 conn_high __attribute__ ((packed)); + __u8 completion_code __attribute__ ((packed)); + __u8 connection_state __attribute__ ((packed)); + __u8 data[0] __attribute__ ((packed)); +}; #define NCP_BINDERY_USER (0x0001) diff --git a/ncp_fs.h b/ncp_fs.h index ae1fdef..a8d4fdd 100644 --- a/ncp_fs.h +++ b/ncp_fs.h @@ -50,10 +50,10 @@ struct ncp_ioctl_request { #define NCP_SUPER_MAGIC 0x564c -#define NCP_SBP(sb) ((struct ncp_server *)(sb->u.generic_sbp)) -#define NCP_INOP(inode) ((struct ncp_inode_info *)(inode->u.generic_ip)) +#define NCP_SBP(sb) ((struct ncp_server *)((sb)->u.generic_sbp)) +#define NCP_INOP(inode) ((struct ncp_inode_info *)((inode)->u.generic_ip)) -#define NCP_SERVER(inode) NCP_SBP(inode->i_sb) +#define NCP_SERVER(inode) NCP_SBP((inode)->i_sb) #define NCP_FINFO(inode) (&(NCP_INOP(inode)->finfo)) static inline int min(int a, int b) { @@ -124,7 +124,6 @@ int ncp_ioctl (struct inode * inode, struct file * filp, /* linux/fs/ncpfs/inode.c */ struct super_block *ncp_read_super(struct super_block *sb, void *raw_data, int silent); -int ncp_notify_change(struct inode *inode, struct iattr *attr); void ncp_invalidate_connection(struct ncp_server *server); int ncp_conn_is_valid(struct ncp_server *server); diff --git a/ncpfs-0.1.lsm b/ncpfs-0.2.lsm similarity index 61% rename from ncpfs-0.1.lsm rename to ncpfs-0.2.lsm index d5b2072..e2559f8 100644 --- a/ncpfs-0.1.lsm +++ b/ncpfs-0.2.lsm @@ -1,14 +1,14 @@ Begin3 Title: ncpfs -Version: 0.1 +Version: 0.2 Entered-date: 19. October 1995 Description: With ncpfs you can mount volumes of your novell server under Linux. -Keywords: filesystem kernel ncp novell +Keywords: filesystem kernel ncp novell netware Author: lendecke@namu01.gwdg.de (Volker Lendecke) Maintained-by: lendecke@namu01.gwdg.de (Volker Lendecke) -Primary-site: linux01.gwdg.de:/pub/smbfs - ~30k ncpfs-0.1.tgz - ~ 1k ncpfs-0.1.lsm +Primary-site: linux01.gwdg.de:/pub/ncpfs + ~44k ncpfs-0.2.tgz + ~ 1k ncpfs-0.2.lsm Copying-policy: GPL End diff --git a/ncplib.c b/ncplib.c index a500fb7..d3c63e3 100644 --- a/ncplib.c +++ b/ncplib.c @@ -126,6 +126,19 @@ ncp_add_mem(struct ncp_server *server, const char *source, int size) return; } +#ifdef __KERNEL__ + +static void +ncp_add_mem_fromfs(struct ncp_server *server, const char *source, int size) +{ + assert_server_locked(server); + memcpy_fromfs(&(server->packet[server->current_size]), source, size); + server->current_size += size; + return; +} + +#endif + static void ncp_add_pstring(struct ncp_server *server, const char *s) { @@ -536,6 +549,176 @@ ncp_close_file(struct ncp_server *server, const char *file_id) return 0; } +static int +ncp_do_create(struct ncp_server *server, + int dir_handle, const char *path, + int attr, + struct ncp_file_info *target, + int function) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, dir_handle); + ncp_add_byte(server, attr); + ncp_add_pstring(server, path); + + if ((result = ncp_request(server, function)) != 0) { + ncp_printf("ncp_request_error: %d\n", result); + ncp_unlock_server(server); + return result; + } + + memcpy(&(target->file_id), ncp_reply_data(server, 0), + NCP_FILE_ID_LEN); + + memset(&(target->file_name), 0, sizeof(target->file_name)); + memcpy(&(target->file_name), ncp_reply_data(server, 8), + NCP_MAX_FILENAME); + + target->file_attributes = ncp_reply_byte(server, 22); + target->file_mode = ncp_reply_byte(server, 23); + target->file_length = ntohl(ncp_reply_dword(server, 24)); + target->creation_date = ntohs(ncp_reply_word(server, 28)); + target->access_date = ntohs(ncp_reply_word(server, 30)); + target->update_date = ntohs(ncp_reply_word(server, 32)); + target->update_time = ntohs(ncp_reply_word(server, 34)); + + ncp_unlock_server(server); + return 0; +} + +int +ncp_create_newfile(struct ncp_server *server, + int dir_handle, const char *path, + int attr, + struct ncp_file_info *target) +{ + return ncp_do_create(server, dir_handle, path, attr, target, 77); +} + +int +ncp_create_file(struct ncp_server *server, + int dir_handle, const char *path, + int attr, + struct ncp_file_info *target) +{ + return ncp_do_create(server, dir_handle, path, attr, target, 67); +} + +int +ncp_erase_file(struct ncp_server *server, + int dir_handle, const char *path, + int attr) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, dir_handle); + ncp_add_byte(server, attr); + ncp_add_pstring(server, path); + + if ((result = ncp_request(server, 68)) != 0) { + ncp_printf("ncp_request_error: %d\n", result); + ncp_unlock_server(server); + return result; + } + + ncp_unlock_server(server); + return 0; +} + +int +ncp_rename_file(struct ncp_server *server, + int old_handle, const char *old_path, + int attr, + int new_handle, const char *new_path) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, old_handle); + ncp_add_byte(server, attr); + ncp_add_pstring(server, old_path); + ncp_add_byte(server, new_handle); + ncp_add_pstring(server, new_path); + + if ((result = ncp_request(server, 69)) != 0) { + ncp_printf("ncp_request_error: %d\n", result); + ncp_unlock_server(server); + return result; + } + + ncp_unlock_server(server); + return 0; +} + +int +ncp_create_directory(struct ncp_server *server, + int dir_handle, const char *path, + int inherit_mask) +{ + int result; + + ncp_init_request_s(server, 10); + ncp_add_byte(server, dir_handle); + ncp_add_byte(server, inherit_mask); + ncp_add_pstring(server, path); + + if ((result = ncp_request(server, 22)) != 0) { + ncp_printf("ncp_request_error: %d\n", result); + ncp_unlock_server(server); + return result; + } + + ncp_unlock_server(server); + return 0; +} + +int +ncp_delete_directory(struct ncp_server *server, + int dir_handle, const char *path) +{ + int result; + + ncp_init_request_s(server, 11); + ncp_add_byte(server, dir_handle); + ncp_add_byte(server, 0); /* reserved */ + ncp_add_pstring(server, path); + + if ((result = ncp_request(server, 22)) != 0) { + ncp_printf("ncp_request_error: %d\n", result); + ncp_unlock_server(server); + return result; + } + + ncp_unlock_server(server); + return 0; +} + +int +ncp_rename_directory(struct ncp_server *server, + int dir_handle, + const char *old_path, const char *new_path) +{ + int result; + + ncp_init_request_s(server, 15); + ncp_add_byte(server, dir_handle); + ncp_add_pstring(server, old_path); + ncp_add_pstring(server, new_path); + + if ((result = ncp_request(server, 22)) != 0) { + ncp_printf("ncp_request_error: %d\n", result); + ncp_unlock_server(server); + return result; + } + + ncp_unlock_server(server); + return 0; +} + + #ifndef __KERNEL__ int @@ -565,9 +748,35 @@ ncp_read(struct ncp_server *server, const char *file_id, return 0; } +int +ncp_write(struct ncp_server *server, const char *file_id, + __u32 offset, __u16 to_write, + const char *source, int *bytes_written) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 0); + ncp_add_mem(server, file_id, 6); + ncp_add_dword(server, htonl(offset)); + ncp_add_word(server, htons(to_write)); + ncp_add_mem(server, source, to_write); + + if ((result = ncp_request(server, 73)) != 0) { + ncp_printf("ncp_request_error: %d\n", result); + ncp_unlock_server(server); + return result; + } + + *bytes_written = to_write; + + ncp_unlock_server(server); + return 0; +} + #else -/* We have to read into user space */ +/* We have to transfer to/from user space */ int ncp_read(struct ncp_server *server, const char *file_id, __u32 offset, __u16 to_read, @@ -595,4 +804,30 @@ ncp_read(struct ncp_server *server, const char *file_id, return 0; } +int +ncp_write(struct ncp_server *server, const char *file_id, + __u32 offset, __u16 to_write, + const char *source, int *bytes_written) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 0); + ncp_add_mem(server, file_id, 6); + ncp_add_dword(server, htonl(offset)); + ncp_add_word(server, htons(to_write)); + ncp_add_mem_fromfs(server, source, to_write); + + if ((result = ncp_request(server, 73)) != 0) { + ncp_printf("ncp_request_error: %d\n", result); + ncp_unlock_server(server); + return result; + } + + *bytes_written = to_write; + + ncp_unlock_server(server); + return 0; +} + #endif diff --git a/ncplib.h b/ncplib.h index 49797ba..65d954d 100644 --- a/ncplib.h +++ b/ncplib.h @@ -94,9 +94,51 @@ ncp_open_file(struct ncp_server *server, int ncp_close_file(struct ncp_server *server, const char *file_id); +int +ncp_create_newfile(struct ncp_server *server, + int dir_handle, const char *path, + int attr, + struct ncp_file_info *target); + +int +ncp_create_file(struct ncp_server *server, + int dir_handle, const char *path, + int attr, + struct ncp_file_info *target); + +int +ncp_erase_file(struct ncp_server *server, + int dir_handle, const char *path, + int attr); + +int +ncp_rename_file(struct ncp_server *server, + int old_handle, const char *old_path, + int attr, + int new_handle, const char *new_path); + +int +ncp_create_directory(struct ncp_server *server, + int dir_handle, const char *path, + int inherit_mask); + +int +ncp_delete_directory(struct ncp_server *server, + int dir_handle, const char *path); + +int +ncp_rename_directory(struct ncp_server *server, + int dir_handle, + const char *old_path, const char *new_path); + int ncp_read(struct ncp_server *server, const char *file_id, - __u32 start, __u16 to_read, + __u32 offset, __u16 to_read, char *target, int *bytes_read); +int +ncp_write(struct ncp_server *server, const char *file_id, + __u32 offset, __u16 to_write, + const char *source, int *bytes_written); + #endif /* _NCPLIB_H */ diff --git a/ncpmount.c b/ncpmount.c index 2bb6be9..7922945 100644 --- a/ncpmount.c +++ b/ncpmount.c @@ -15,13 +15,11 @@ #include #include #include -#include -#include #include -#include /* #include */ /* generates a warning here */ extern pid_t waitpid(pid_t, int *, int); #include +#include #include #include #include @@ -38,8 +36,54 @@ extern pid_t waitpid(pid_t, int *, int); #include "ipxutil.h" static char *progname; -static char *mount_point; -static char *server_name; + + +static void +str_upper(char *name) +{ + while (*name) { + *name = toupper(*name); + name = name + 1; + } +} + +static char * +fullpath(const char *p) +{ + char path[MAXPATHLEN]; + + if (realpath(p, path) == NULL) + return strdup(p); + else + return strdup(path); +} + +static void +usage(void) +{ + printf("usage: %s server mount-point [options]\n", progname); + printf("Try `%s -h' for more information\n", progname); +} + +static void +help(void) +{ + printf("\n"); + printf("usage: %s server mount-point [options]\n", progname); + printf("\n" + "-U username Username sent to server\n" + "-u uid uid the mounted files get\n" + "-g gid gid the mounted files get\n" + "-f mode permission the files get (octal notation)\n" + "-d mode permission the dirs get (octal notation)\n" + "-C Don't convert password to uppercase\n" + "-P password Use this password\n" + "-n Do not use any password\n" + " If neither -P nor -n are given, you are\n" + " asked for a password.\n" + "-h print this help text\n" + "\n"); +} struct sap_query { unsigned short query_type; /* net order */ @@ -47,15 +91,14 @@ struct sap_query { }; struct sap_server_ident { - unsigned short server_type; - char server_name[48]; - IPXNet server_network; - IPXNode server_node; - IPXPort server_port; - unsigned short intermediate_network; -} __attribute__ ((packed)); + unsigned short server_type __attribute__ ((packed)); + char server_name[48] __attribute__ ((packed)); + IPXNet server_network __attribute__ ((packed)); + IPXNode server_node __attribute__ ((packed)); + IPXPort server_port __attribute__ ((packed)); + unsigned short intermediate_network __attribute__ ((packed)); +}; - void ipx_fprint_node(FILE* file,IPXNode node) { @@ -212,33 +255,217 @@ ipx_sap_find_server(char *name, int server_type, int timeout, return res; } -int ipx_sscanf_node(char *buf, unsigned char node[6]) +int +ipx_sscanf_node(char *buf, unsigned char node[6]) { - int i; - int n[6]; + int i; + int n[6]; - if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x", - &(n[0]), &(n[1]), &(n[2]), - &(n[3]), &(n[4]), &(n[5]))) != 6) { - return i; - } + if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x", + &(n[0]), &(n[1]), &(n[2]), + &(n[3]), &(n[4]), &(n[5]))) != 6) { + return i; + } - for (i=0; i<6; i++) { - node[i] = n[i]; - } - return 6; + for (i=0; i<6; i++) { + node[i] = n[i]; + } + return 6; } -int -main(int argc, char **argv) +static int +parse_args(int argc, char *argv[], struct ncp_mount_data *data, + int *got_password, int *upcase_password) { - struct ncp_mount_data data; - struct stat st; - struct sockaddr_ipx addr; - int ncp_sock, wdog_sock; - int flags; + int opt; + struct passwd *pwd; + struct group *grp; - progname = argv[0]; + *got_password = 0; + *upcase_password = 1; + + while ((opt = getopt (argc, argv, "Cp:s:c:U:u:g:f:d:m:P:n")) != EOF) { + switch (opt) { + case 'C': + *upcase_password = 0; + break; + case 'U': + if (strlen(optarg) > 63) { + fprintf(stderr, "Username too long: %s\n", + optarg); + return 1; + } + strcpy(data->username, optarg); + break; + case 'u': + if (isdigit(optarg[0])) { + data->uid = atoi(optarg); + } else { + pwd = getpwnam(optarg); + if (pwd == NULL) { + fprintf(stderr, "Unknown user: %s\n", + optarg); + return 1; + } + data->uid = pwd->pw_uid; + } + break; + case 'g': + if (isdigit(optarg[0])) { + data->gid = atoi(optarg); + } else { + grp = getgrnam(optarg); + if (grp == NULL) { + fprintf(stderr, "Unknown group: %s\n", + optarg); + return 1; + } + data->gid = grp->gr_gid; + } + break; + case 'f': + data->file_mode = strtol(optarg, NULL, 8); + break; + case 'd': + data->dir_mode = strtol(optarg, NULL, 8); + break; + case 'P': + strcpy(data->password, optarg); + *got_password = 1; + break; + case 'n': + data->password[0] = '0'; + *got_password = 1; + break; + default: + return -1; + } + } + return 0; + +} + +/* Returns 0 if the filesystem is in the kernel after this routine + completes */ +static int +load_ncpfs() +{ + FILE *fver, *ffs; + char s[1024]; + char modname[1024]; + char *p, *p1; + pid_t pid; + int status; + + /* Check if ncpfs is in the kernel */ + ffs = fopen("/proc/filesystems", "r"); + if (ffs == NULL) { + perror("Error: \"/proc/filesystems\" could not be read:"); + return -1; + } + p = NULL; + while (! feof(ffs)) { + p1 = fgets(s, sizeof(s), ffs); + if (p1) { + p = strstr(s, "ncpfs"); + if (p) { + break; + } + } + } + fclose(ffs); + if (p) { + return 0; + } + fver = fopen("/proc/version", "r"); + if (fver == NULL) { + perror("Error: \"/proc/version\" could not be read:"); + return -1; + } + fgets(s, 1024, fver); + fclose(fver); + p = strstr(s, "version "); + if (p == NULL) { + version_error: + fprintf(stderr, "Error: Unable to determine the Linux version" + "from \"/proc/version\n"); + return -1; + } + p = strchr(p, ' ') + 1; + p1 = strchr(p, ' '); + if (p1 == NULL) { + goto version_error; + } + strcpy(modname, "/lib/modules/"); + strncat(modname, p, p1 - p); + strcat(modname, "/ncpfs.o"); + + /* system() function without signal handling, from Stevens */ + + if ((pid = fork()) < 0) { + return 1; + } else if (pid == 0) { + /* child */ + execl("/sbin/insmod", "insmod", modname, NULL); + _exit(127); /* execl error */ + } else { + /* parent */ + while (waitpid(pid, &status, 0) < 0) { + if (errno != EINTR) { + status = -1; + break; + } + } + } + return status; +} + +/* Check whether user is allowed to mount on the specified mount point */ +static int +mount_ok(struct stat *st) +{ + if (!S_ISDIR(st->st_mode)) + { + errno = ENOTDIR; + return -1; + } + + if ( (getuid() != 0) + && ( (getuid() != st->st_uid) + || ((st->st_mode & S_IRWXU) != S_IRWXU))) + { + errno = EPERM; + return -1; + } + + return 0; +} + + + +int +main(int argc, char *argv[]) +{ + struct ncp_mount_data data; + struct sockaddr_ipx addr; + struct stat st; + + int fd; + int Got_Password; + int Upcase_Password; + int um; + unsigned int flags; + char hostname[MAXHOSTNAMELEN + 1]; + + char *server_name; + char *mount_point; + + struct mntent ment; + FILE *mtab; + + int ncp_sock, wdog_sock; + + progname = argv[0]; if (geteuid() != 0) { fprintf(stderr, "%s must be installed suid root\n", progname); @@ -247,22 +474,43 @@ main(int argc, char **argv) memset(&data, 0, sizeof(struct ncp_mount_data)); - if (argc != 5) { - fprintf(stderr, "usage: %s server mount-point" - " user password\n", progname); - exit(1); - } + memset(hostname, '\0', MAXHOSTNAMELEN+1); + gethostname(hostname, MAXHOSTNAMELEN); - server_name = argv[1]; - mount_point = argv[2]; - + if (argc < 3) { + if ( (argc == 2) + && (argv[1][0] == '-') + && (argv[1][1] == 'h') + && (argv[1][2] == '\0')) { - if (stat(mount_point, &st) == -1) { + help(); + return 0; + } + else + { + usage(); + return -1; + } + } + + server_name = argv[1]; + mount_point = argv[2]; + + argv += 2; + argc -= 2; + + if (stat(mount_point, &st) == -1) { fprintf(stderr, "could not find mount point %s: %s\n", mount_point, strerror(errno)); exit(1); } + if (mount_ok(&st) != 0) { + fprintf(stderr, "cannot to mount on %s: %s\n", + mount_point, strerror(errno)); + exit(1); + } + ncp_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX); if (ncp_sock == -1) { fprintf(stderr, "could not open ncp socket: %s\n", @@ -297,10 +545,13 @@ main(int argc, char **argv) exit(1); } - printf("server: "); - ipx_fprint_saddr(stdout, &addr); - printf("\n"); - + /* Check if the ncpfs filesystem is in the kernel. If not, attempt + * to load the ncpfs module */ + if (load_ncpfs() != 0) { + fprintf(stderr, "Error: Unable to start ncpfs, exiting...\n"); + exit(1); + } + data.version = NCP_MOUNT_VERSION; data.ncp_fd = ncp_sock; data.wdog_fd = wdog_sock; @@ -309,24 +560,111 @@ main(int argc, char **argv) strcpy(data.server_name, server_name); data.time_out = 20; /* 2 seconds */ data.retry_count = 2; - data.uid = 501; /* me */ - data.gid = 100; /* users */ - data.file_mode = data.dir_mode = S_IRWXU|S_IRWXG|S_IRWXO; - strcpy(data.username, argv[3]); - strcpy(data.password, argv[4]); + + /* getuid() gives us the real uid, who may umount the fs */ + data.mounted_uid = getuid(); + + if (getenv("USER")) { + strcpy(data.username, getenv("USER")); + str_upper(data.username); + } + + if (data.username[0] == 0 && getenv("LOGNAME")) + { + strcpy(data.username,getenv("LOGNAME")); + str_upper(data.username); + } + + data.uid = getuid(); + data.gid = getgid(); + um = umask(0); + umask(um); + data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~um; + data.dir_mode = 0; + + if (parse_args(argc, argv, &data, &Got_Password, + &Upcase_Password) != 0) { + usage(); + return -1; + } + + if (data.dir_mode == 0) { + data.dir_mode = data.file_mode; + if ((data.dir_mode & S_IRUSR) != 0) + data.dir_mode |= S_IXUSR; + if ((data.dir_mode & S_IRGRP) != 0) + data.dir_mode |= S_IXGRP; + if ((data.dir_mode & S_IROTH) != 0) + data.dir_mode |= S_IXOTH; + } + + if (Got_Password == 0) { + strcpy(data.password, getpass("Password: ")); + } + + if (Upcase_Password == 1) { + str_upper(data.password); + } + + if (data.server_name[0] == '\0') { + strcpy(data.server_name, server_name); + str_upper(data.server_name); + } flags = MS_MGC_VAL; - if (mount(NULL, mount_point, "ncpfs", flags, (char *)&data) < 0) { + if (mount(NULL, mount_point, "ncpfs", + flags, (char *)&data) < 0) { perror("mount error"); - fprintf(stderr, "Maybe you should try your password in " - "upper case\n"); + close(wdog_sock); + close(ncp_sock); + printf("Maybe you should try to type the username and\n" + "password in UPPERCASE.\n"); return -1; } close(ncp_sock); close(wdog_sock); - return 0; -} + ment.mnt_fsname = server_name; + ment.mnt_dir = fullpath(mount_point); + ment.mnt_type = "ncpfs"; + ment.mnt_opts = ""; + ment.mnt_freq = 0; + ment.mnt_passno= 0; + mount_point = ment.mnt_dir; + + if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) + { + fprintf(stderr, "Can't get "MOUNTED"~ lock file"); + return 1; + } + close(fd); + + if ((mtab = setmntent(MOUNTED, "a+")) == NULL) + { + fprintf(stderr, "Can't open " MOUNTED); + return 1; + } + + if (addmntent(mtab, &ment) == 1) + { + fprintf(stderr, "Can't write mount entry"); + return 1; + } + if (fchmod(fileno(mtab), 0644) == -1) + { + fprintf(stderr, "Can't set perms on "MOUNTED); + return 1; + } + endmntent(mtab); + + if (unlink(MOUNTED"~") == -1) + { + fprintf(stderr, "Can't remove "MOUNTED"~"); + return 1; + } + + return 0; +} diff --git a/ncptest.c b/ncptest.c new file mode 100644 index 0000000..a914ac7 --- /dev/null +++ b/ncptest.c @@ -0,0 +1,173 @@ +/* + * ncpmount.c + * + * Copyright (C) 1995 by Volker Lendecke + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* #include */ /* generates a warning here */ +extern pid_t waitpid(pid_t, int *, int); +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "ncplib.h" +#include "ipxutil.h" + +static char *progname; +static char *mount_point; + +void +test_filesearch(struct ncp_server *server) +{ + struct ncp_filesearch_info fsinfo; + struct ncp_file_info finfo; + + if (ncp_file_search_init(server, 0, "sys:\\public", &fsinfo) != 0) { + printf("could not fs init\n"); + return; + } + + while (ncp_file_search_continue(server, &fsinfo, + 0, + "*", &finfo) == 0) { + printf("name: %s\n", finfo.file_name); + } + return; +} + +void +test_getfinfo(struct ncp_server *server) +{ + struct ncp_file_info finfo; + + ncp_get_finfo(server, 0, "sys:", "public", &finfo); + ncp_get_finfo(server, 0, "sys:login", "login.exe", &finfo); +} + +void +testopen(struct ncp_server *server) +{ + struct ncp_file_info finfo; + char buf[1025]; + int bytes_read; + + ncp_open_file(server, 0, "sys:\\etc\\samples\\protocol", 0, + AR_READ|AR_WRITE, + &finfo); + if (ncp_read(server, finfo.file_id, 0, 1024, buf, &bytes_read) == 0) { + printf("bytes: %d\n", bytes_read); + buf[bytes_read]=0; + puts(buf); + } + + ncp_close_file(server, finfo.file_id); +} + +void +testcreate(struct ncp_server *server) +{ + + if (ncp_rename_file(server, 0, "sys:\\me\\blub.txt", 0, + 0, "sys:\\me\\blub1.txt") != 0) { + printf("create war nix\n"); + } + if (ncp_create_directory(server, 0, "sys:\\me\\blubdir", 0xff) != 0) { + printf("mkdir war nix\n"); + } + if (ncp_rename_directory(server, 0, "sys:\\me\\blubdir", + "\\me\\blubneu") != 0) { + printf("mvdir war nix\n"); + return; + } + if (ncp_delete_directory(server, 0, "sys:\\me\\blubneu") != 0) { + printf("rmdir war nix\n"); + return; + } + + +} + +int +main(int argc, char **argv) +{ + struct ncp_mount_data data; + struct stat st; + struct ncp_server serv; + struct ncp_server *server = &serv; + + + progname = argv[0]; + + if (geteuid() != 0) { + fprintf(stderr, "%s must be installed suid root\n", progname); + exit(1); + } + + memset(&data, 0, sizeof(struct ncp_mount_data)); + + if (argc == 2) { + mount_point = argv[1]; + } else { + fprintf(stderr, "usage: %s mount-point\n", progname); + printf("defaulting to %s mnt\n", progname); + mount_point = "mnt"; + } + + + if (stat(mount_point, &st) == -1) { + fprintf(stderr, "could not find mount point %s: %s\n", + mount_point, strerror(errno)); + exit(1); + } + + server->mount_fid = open(mount_point, O_RDONLY, 0); + + if (server->mount_fid == -1) { + fprintf(stderr, "Could not open %s: %s\n", + mount_point, strerror(errno)); + return -1; + } + +#if 0 + for (i=0; i<5; i++) { + struct ncp_volume_info info; + ncp_get_volume_info_with_number(server, i, &info); + printf("vol %d: %s\n", i, info.volume_name); + } + + test_filesearch(server); + test_getfinfo(server); + + +#endif + + testcreate(server); + + return 0; +} + diff --git a/nwcrypt.c b/nwcrypt.c index eceafe8..d12e1c2 100644 --- a/nwcrypt.c +++ b/nwcrypt.c @@ -1,9 +1,7 @@ /*$********************************************************* $* $* This code has been taken from DDJ 11/93, from an -$* article by Pawel Szczerbina. Please read the file -$* README for my questions about the legal status of -$* this code. +$* article by Pawel Szczerbina. $* $* Password encryption routines follow. $* Converted to C from Barry Nance's Pascal @@ -15,6 +13,77 @@ $* October 1995. $* $**********************************************************/ +/**************************************************************************** + +I read that Novell is not very open when it comes to technical details +of the Netware Core Protocol. This might be especially true for the +encryption stuff. I took the necessary code from Dr. Dobb's Journal +11/93, Undocumented Corner. I asked Jon Erickson about +the legal status of this piece of code: + + +--- +Date: Thu, 12 Oct 1995 13:44:18 +0100 +From: Volker Lendecke +To: jon@ddj.com +Subject: legal status of your source code? + + +Hello! + +I hope that you're the right one to write to, you are the first on your WWW +server. If you are not, could you please forward this message to the right +person? Thanks. + +I'm currently exploring the possibility to write a free (in the GNU GPL +sense) NCP filesystem, which would allow me to access a novell server +transparently. For that I would like to use the encryption functions you +published in DDJ 11/93, Undocumented Corner. I would make some cosmetic +changes, such as other indentations, minor code changes and so on. But I do +not know if that allows me to publish this code under GPL. One alternative +would be to publish a diff against your listing, but that would probably +contain much of your code as well, and it would be very inconvenient for +the average user. + +I think that you have some kind of standard procedure for such a +case. Please tell me what I should do. + +Many thanks in advance, + + Volker + + +=================================================================+ + ! Volker Lendecke Internet: lendecke@namu01.gwdg.de ! + ! D-37081 Goettingen, Germany ! + +=================================================================+ + +-- + + +I got the following answer: + +--- +From: Jon Erickson +X-Mailer: SCO System V Mail (version 3.2) +To: lendecke@namu01.gwdg.de +Subject: Re: legal status of your source code? +Date: Thu, 12 Oct 95 5:42:56 PDT + +Volker, +Code from Dr. Dobb's Journal related articles is provided for +anyone to use. Clearly, the author of the article should be +given credit. +Jon Erickson + +--- + +With this answer in mind, I took the code and made it a bit more +C-like. The original seemed to be translated by a mechanical pascal->c +translator. Jon's answer encouraged me to publish nwcrypt.c under the +GPL. If anybody who knows more about copyright and sees any problems +with this, please tell me. +****************************************************************************/ + /******************* Data types ***************************/ typedef unsigned char buf32[32]; typedef unsigned char buf16[16]; diff --git a/start_ipx b/start_ipx new file mode 100755 index 0000000..624b58d --- /dev/null +++ b/start_ipx @@ -0,0 +1,7 @@ +#!/bin/sh +# +# abcd is my ipx network number and 1234 my server's internal network number. +# 00001b038b11 is the server's node number. +# +ipx_interface add -p eth0 EtherII abcd +ipx_route add 1234 abcd 00001b038b11 diff --git a/startnet b/startnet deleted file mode 100755 index b8baed8..0000000 --- a/startnet +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -ipx_interface add -p eth0 EtherII abcd -ipx_route add 1234 abcd 00001b038b11